How does CHIP 8 graphics rendered on screen? - javascript

Opcode DXYN:
Draws a sprite at coordinate (VX, VY) that has a width of 8 pixels and a height of N pixels. Each row of 8 pixels is read as bit-coded (with the most significant bit of each byte displayed on the left) starting from memory location I; I value doesn't change after the execution of this instruction. As described above, VF is set to 1 if any screen pixels are flipped from set to unset when the sprite is drawn, and to 0 if that doesn't happen.
Basically I have an array called graphics which is a double array constructed out of 64 rows of new arrays per each with 32 columns.
//Creating new double arrays for storing graphics data
graphics = new Array(GFX_WIDTH);
for(var i = 0; i < graphics .length; i++){
graphics [i] = new Array(GFX_HEIGHT);
for(var j = 0; j < graphics [i].length; j++){
graphics [i][j] = 0;
}
}
and inside these arrays, I am storing graphics data as described above. My question is, do I just have to draw a square when an array element is 1 and empty that space when it's 0? According to a blog article on CHIP8, there is an extra array for font-set but what's the usage of it?
The blog article I have mentioned above
http://www.multigesture.net/articles/how-to-write-an-emulator-chip-8-interpreter/
Thank you.

First of all, note that the pixels are bitpacked - each byte will contain 8 pixels of sprite data. In other words, the byte 0xAA is a single-pixel tall sprite with the first, third, fifth and seventh pixel set.
When drawing your sprite, you need to loop through each bit. If the bit is set, you flip the corresponding bit in your display - 0 becomes 1 and 1 becomes 0. This can, for example, be done by applying the XOR (^) operation to your display byte.
Note, however, that VF must be set to 1 if any pixels go from 1 to 0 in the process, and 0 if no pixels are unset - so you also need to do this. I find it is easiest to read if you have an if that checks whether or not to flip a bit, and then take care of both flipping and VF-updating inside that if.
For reference, my own Delphi implementation of this opcode looks like this:
procedure TChip8CPU.OpcodeD(inst: TInstruction);
var
X, Y, cX, cY, data: byte;
begin
Reg[$F] := 0;
for Y := 0 to inst.NibbleArg - 1 do begin
cY := (Reg[inst.Y] + Y) mod HEIGHT;
data := Memory[AddressI + Y];
for X := 0 to 7 do begin
if (data and ($80 shr X)) <> 0 then begin
cX := (Reg[inst.X] + X) mod WIDTH;
if Display[cY, cX] = 1 then Reg[$F] := 1;
Display[cY, cX] := Display[cY, cX] xor 1;
end;
end;
end;
end;
Note that for sprites which go outside the screen boundaries, they wrap around (this is done by the mod WIDTH/mod HEIGHT parts). This is mentioned in Cowgod's Chip-8 Technical Reference.

Related

Is there a way to draw hundreds of points faster (p5.js)

I am making a program to test out my attempt at a Perlin Noise generating algorithm. The Perlin noise itself seems fine, however I've found that drawing that noise on the canvas is very slow. This is probably because for every single point in the canvas I have to call the stroke() function to change the color of the next pixel, then draw that pixel. This is done over a 400*400 pixel canvas, so I am changing the color with stroke() 160,000 times and calling point() 160,000 times.
This takes some time to do. I was wondering if there is any way of making this faster. Perhaps if I could turn the Perlin noise into an image, then load that image instead of drawing all 160,000 points individually?
The code of my draw loop is below
function draw() {
background(220);
strokeWeight(1);
for(var row = 0; row < height; row ++)
{
for(var column = 0; column < width; column ++)
{
//takes a noise value from the myNoise array whose elements have a range of [-1,1] and turns it into a value from [0,256], and makes that the color of the next point
stroke((myNoise[row][column]+1)*128);
point(column,row)
}
}
noLoop();
}
Edit: I used the following code to create and load an image. Credit to Samathingamajig for the tip.
function draw() {
background(220);
img = createImage(width,height);
img.loadPixels();
for(var row = 0; row < height; row ++)
{
for(var column = 0; column < width; column ++)
{
//takes a noise value from the myNoise array whose elements have a range of [-1,1] and turns it into a value from [0,256], and makes that the color of the next pixel in the image
img.set(row,column,color((myNoise[row][column]+1)*128))
}
}
img.updatePixels();
image(img,0,0)
noLoop();
}
Also Samathingamajig pointed out that 400*400 is 160,000, not 1,600, which I have changed above.
My original code took about 4 seconds to run the draw loop. This new version takes about 0.75 seconds.
I also tested using the createGraphics() method as suggested by rednoyz. This was not as fast as using the image methods because it still requires me to call stroke() 160,000 times.
Both of these solutions gave me an image that I could very quickly draw, however createImage() allowed me to create the image in much less time than createGraphics() did.
Just to add a bit of nuance to the existing suggestion:
use pixels[] instead of set(x, y, color): it's less intuitive to think of a 1D index that takes into account [r,g,b,a,...] pixels order, and (pixelDensity on retina displays), but it is faster.
The documentation mentions:
Setting the color of a single pixel with set(x, y) is easy, but not as
fast as putting the data directly into pixels[]. Setting the pixels[]
values directly may be complicated when working with a retina display,
but will perform better when lots of pixels need to be set directly on
every loop.
In your case that would roughly look like this:
img.loadPixels();
let numPixels = width * height;
for(let pixelIndex = 0; pixelIndex < numPixels; pixelIndex ++)
{
//takes a noise value from the myNoise array whose elements have a range of [-1,1] and turns it into a value from [0,256], and makes that the color of the next pixel in the image
// index of red channel for the current pixel
// pixels = [r0, g0, b0, a0, r1, g1, b1, a1, ...]
let redIndex = pixelIndex * 4;
// convert 1D array index to 2D array indices
let column = pixelIndex % width;
let row = floor(pixelIndex / width);
// get perlin noise value
let grey = (myNoise[row][column]+1) * 128;
// apply grey value to R,G,B channels (and 255 to alpha)
img.pixels[redIndex] = grey; // R
img.pixels[redIndex + 1] = grey; // G
img.pixels[redIndex + 2] = grey; // B
img.pixels[redIndex + 3] = 255; // A
}
img.updatePixels();
(also looping once instead of nested looping will help).
Regarding point(), it might use something like beginShape(POINTS);vertex(x,y);endShape(); behind the scenes which means something like this would be slightly more efficient:
let numPixels = width * height;
beginShape(POINTS);
for(let pixelIndex = 0; pixelIndex < numPixels; pixelIndex ++)
{
//takes a noise value from the myNoise array whose elements have a range of [-1,1] and turns it into a value from [0,256], and makes that the color of the next pixel in the image
// convert 1D array index to 2D array indices
let column = pixelIndex % width;
let row = floor(pixelIndex / width);
// get perlin noise value
stroke(color((myNoise[row][column]+1) * 128));
// apply grey value to R,G,B channels (and 255 to alpha)
vertex(column, row);
}
endShape();
That being said, it might not work as intended:
AFAIK this won't work with createCanvas(400, 400, WEBGL) as currently you can't set an independent stroke to each vertex in a shape.
With the typical Canvas 2D renderer this may still be very slow to render this many vertices using beginShape()/endShape()
Although a more advanced topic, another option that should be fast is shader(). (Might find some perlin noise inspiration on shadertoy.com btw).
p5.js is great to learn with but it's main goal is not to have the most performant canvas renderers. If shaders are a bit too complex at this stage, but you're comfortable with javascript in general, you can look at other libraries such as pixi.js (maybe pixi particle-emitter could be handy ?)
I've tried a lot of millisecond tests, and the image approach is by FAR the best. The problem is really just the amount of pixels you're trying to process as #Samathinamajig pointed out.
testing: https://editor.p5js.org/KoderM/sketches/6XPirw_98s

How to plot this type of "binary matrix" graphic (I honestly don't know if it has a name) using PHP and HTML

I'm trying to plot this type of "binary matrix" graphic:
Disregard the two colors from the sample image; I want to either color a dot blue for, let's say, "complete" values or leave it uncolored/gray for "incomplete" values as a way to track daily task completion for a certain amount of dots/days. The dots represent a day where a task was completed or not completed. Showing the full amount of dots/days gives perspective on % of completion as days go by.
I would like to use a combination of HTML/Javascript and PHP + MySQL. But the hardest part for me is figuring out a good algorithm to render this visualization. Thanks for your help.
Just treat each dot like it's a pixel. Also, imagine that the image has been rotated 90° CCW. Then, you simply draw a square that takes up less room that is allocated to it - this way, you get the separating lines.
Here'e a quick something to have a play with.
A few notes:
0) I just halved your image dimensions
1) 4 pixels and 5 pixels were chosen arbitrarily
2) I didn't bother with setting the colour of the dot - you can
easily do this.
3) I've simply treated the drawing area like a normal top-bottom
bitmap, while your image seems to show that all of the Y values will
be used before the next X value is needed. (This is like a 90° CCW
rotation).
4) I'm addressing the pixels with an X and a Y - perhaps you'd be
more interested in addressing them with a single number? If so, you
could easily write a function that would map two coords to a single
number - the pixels index, if you like.
I.e if an image is 100 x 100, there are 10,000 pixels. You could address them by specifying a number from 0 - 9,999
E.g
function 10k_to_100x100(index)
{
var x = index % 100;
var y = (index / 100).toFixed(0);
plotPixelDot(x, y);
}
X is simply the remainder when dividing by the width
Y is the whole number answer when dividing by the width
Here's a snippet you can try right here on the page:
function byId(id){return document.getElementById(id);}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded()
{
var x, y;
for (y=0; y<20; y++)
{
for (x=0; x<100; x++)
{
drawDot(x, y, 'output');
}
}
}
function drawDot(xPos, yPos, canvasId)
{
var actualX=xPos*5, actualY=yPos*5;
var ctx = byId(canvasId).getContext('2d');
ctx.fillRect(actualX, actualY, 4, 4);
}
<canvas width=558 height=122 id='output'></canvas>

Select optimal set of samples to approximate a curve with predetermined number of samples?

Background
I have a pet project that I love to overthink from time to time. The project has to do with an RC aircraft control input device. People familiar with that hobby are probably also familiar with what is known as "stick expo", which is a common feature of RC transmitters where the control sticks are either more or less sensitive near the neutral center position and become less or more sensitive as the stick moves closer to its minimum or maximum values.
I've read some papers that I don't fully understand. I clearly don't have the math background to solve this, so I'm hoping that perhaps one of you might.
Problem
I have decided to approximate the curve by taking a pre-determined number of samples and use linear interpolation to determine output values for any input values between the sample points. I'm trying to find a way to determine the most optimal set of sample points.
If you look at this example of a typical growth curve for this application, you will notice that some sections are more linear (straighter), and some are less linear (more curvy).
These samples are equally distant from each other, but they don't have to be. It would be smart to increase the sample density where there is more change and thereby increasing the resolution in the curvy segments by borrowing redundant points from the straight segments.
Is it possible to quantify the degree of error? If it is, then is it also possible to determine the optimal set of samples for a given function and a pre-determined number of samples?
Reference Code
Snippet from the class that uses a pre-calculated set of points to approximate an output value.
/* This makes the following assumptions:
* 1. The _points[] data member contians at least 2 defined Points.
* 2. All defined Points have x and y values between MIN_VALUE and MAX_VALUE.
* 3. The Points in the array are ordered by ascending values of x.
*/
int InterpolatedCurve::value( int x ) {
if( _points[0].x >= x ) { return _points[0].y; }
for( unsigned int i = 1; i < _point_count; i++ ) {
if( _points[i].x >= x ) {
return map(x, _points[i-1].x, _points[i].x,
_points[i-1].y, _points[i].y);
}
}
// This is an error condition that is not otherwise reported.
// It won't happen as long as the points are set up correctly.
return x;
}
// Example map function (borrowed from Arduino site)
long map( long x, long x1, long x2, long y1, long y2 ) {
return (x - x1) * (y2 - y1) / (x2 - x1) + y1;
}
Although my project is actually in C++, I'm using a Google spreadsheet to produce some numbers while I ponder this problem.
// x: Input value between -1 and 1
// s: Scaling factor for curve between 0 (linear) and 1 (maximum curve)
// c: Tunable constant
function expo_fn( x, s, c ) {
s = typeof s !== 'undefined' ? s : 1.0;
c = typeof c !== 'undefined' ? c : 4.0;
var k = c * ((c - 1.0) * s*s*s + s)/c + 1.0;
return ((k - 1.0) * x*x*x*x*x + x)/k;
};
The following creates a set of isometrically distributed (non-optimal) points between input values -1 and 1. These output values were expanded to integers between -16383 and 16383 for the above example spreadsheet. Factor is a value between 0 and 1 that determines the "curviness"--zero being a flat, linear curve and 1 being the least-linear curve I care to generate.
function Point( x, y ) {
this.x = x;
this.y = y;
};
function compute_points_iso( count, factor ) {
var points = [];
for( var i = 0; i < count; ++i ) {
var x = 2.0/(count - 1.0) * i - 1.0;
var y = expo_fn(x, factor);
points.push(new Point(x,y));
}
return points;
};
Relevant Academic Work
I have been studying this paper describing an algorithm for selecting significant data points, but my program doesn't quite work right yet. I will report back if I ever get this thing working.
The key here is to realize that you can bound the error on your linear interpolation in terms of the second derivative of the function. I.e. if we approximate f(x) \approx f(x_0) + f'(x_0)*(x-x_0), then the error in this approximation is less than abs[ 0.5*f''(x_0)(x-x_0)^2 ].
The outline of an iterative approach could look like this:
Construct an initial, e.g. uniformly spaced, grid
Compute the second derivative of the function on this grid.
Compute the bound on the error using the second-derivative and the inter-sample spacing
Move the samples closer together where the error is large; move them further apart where the error is small.
I'd expect this to be an iterative solution that loops on steps 2,3,4.
Most of the details are in step 4.
For a fixed number of sample points one could use the median of the error bounds to select
where finer/coarser sampling is required (i.e. those locations where the error is larger than the median error will have the sample points pulled closer together).
Let E_0 be this median of the error bounds; then we can, for each sample in the point, compute a new desired sample spacing (dx')^2=2*E_0/f''(x); then you'd need some logic to go through and change the grid spacing so that it is closer to these ideal spacings.
My answer is influenced by having used the "Self-Organizing Map" algorithm on data; this or related algorithms may be relevant for your problem. However, I can't recall ever
seeing a problem like yours where the goal is to make your estimates of the error uniform across the grid.

Arranging rectangles within a boundary without overlap and x contraints

I am trying to arrange an unknown number of rectangles so that they dont overlap each other. There are a number of constraints when rearranging rectangles:
Can ONLY move in the positive y (up) direction with the exception the
condition where moving up will push the rectangle outside of the
container boundary.
CANNOT move in the x (left or right) direction We should get some
reasonable padding in between rectangles on all sides.
The top most rectangle should be the first rectangle (denoted by a label in the jsbin link)
I wrote a small something that would generate the main problem here at jsbin. So far the only thing that comes to my mind is a situation where I iterate through these rectangles back and forth. I was wondering if anyone can suggest an approach or better yet point to an existing solution.
You need to compute the vertical position of each rectangle using the height of the preceding rectangles. It may be useful to check if the problem has a solution.
// Generate random rectangles, with the vertical position set to zero
var padding = 5;
var num_rectangles = 10;
var rectangles = [];
for (var k = 0; k < num_rectangles; k += 1) {
rectangles.push({
x: 50 * Math.random(),
y: padding,
width: Math.max(50 * Math.random(), 20),
height: Math.max(50 * Math.random(), 20)
});
}
// Update the vertical position of the item j as the sum of the heigths
// of the rectangles 0, ..., j - 1
for (var j = 1; j < num_rectangles; j += 1) {
rectangles[j].y = rectangles[j - 1].y + rectangles[j - 1].height + padding;
}
And then just draw the rectangles as usual. I wrote a small example http://jsfiddle.net/FuepP/2/
The only thing I can think of at the moment is basically a branch and bound search. Starting from the bottom, iteratively resolve colliding pairs by pushing one or the other rectangle up (branching). If you go above the limit, backtrack to the previous branch.
I wouldn't be surprised if solving this problem was NP-Complete. It's a more constrained version of the bin packing problem. On the other hand, over-constraining problems tends to make them very easy so maybe it's not NP-Complete. I tried to think of a reduction for a few minutes but didn't come up with anything.

Dithering child elements' dimensions to fill a parent element

Say I have a parent div with width 500px. It has 13 child elements that should fill its width.
If I give each child element a width of 500 / 13 = 38.46... pixels, the browser will floor the pixel values, so I end up with 13 elements that take up a total of 38 * 13 = 494 pixels. There will be 6 pixels on the right side of the parent div that are not filled.
Is there an easy way to dither the child element widths so that the remainder (6 pixels) is distributed among some of the child elements, resulting in a total width of 500 pixels?
If I have to do the calculations manually and there's no way to get the browser to manage it, what dithering algorithm might I use in this case?
EDIT: A clarification -- I'm doing these calculations on the client side using JavaScript. Also, the size of the parent div and the number of child divs vary at runtime; the figures above are just an example.
I'd suggest you just do everything with integer math yourself. You can then calculate what the uneven amount is and then decide how you want to distribute it across the elements. My supposition is that the least noticeable way to distribute the extra pixels would be to keep as many like width elements next to each other as possible.
One way of doing that would to calculate how many extra pixels N you have and then just give each N elements starting from the left one extra pixel. If you were worried about things not being centered, you could allocate the first extra pixel to the far left object, the second extra pixel to the far right, the third extra pixel to the 2nd from left, the fourth extra pixel from the 2nd from right, etc... This would have one more boundary between dissimilar width objects, but be more symmetric than the first algorithm.
Here's some code that shows how one could put the extra pixels on the end elements from outside in:
function distributeWidth(len, totalWidth) {
var results = new Array(len);
var coreWidth = Math.floor(totalWidth / len);
var extraWidth = totalWidth - (coreWidth * len);
var w,s;
for (var i = 0; i < len; i++) {
w = coreWidth;
if (extraWidth > 0) {
w++;
extraWidth--;
}
if (i % 2 == 0) {
s = i/2; // even, index from front of array
} else {
s = len - ((i+1)/2); // odd, index from end of array
}
results[s] = w;
}
return(results)
}
And here's a fiddle to see it in action: http://jsfiddle.net/jfriend00/qpFtT/2/

Categories