Last clicked image in array - arrays

I have an array of images, when i click on one of them, I want it to loop and create a pattern. (This part already works). When i want to get the last clicked image out of my array i get a 'NullPointerException'
PImage[] patronen = new PImage[7];
int pLength = patronen.length;
PImage selectedPatroon = patronen[patronen.length-1];
void setup(){
size(1024, 768);
}
void draw(){
createPGrid();
image(selectedPatroon, xPos, yPos);
}
void createPGrid(){
for(int j = 0; j < gpLength; j++){
// Grid maanmaken
xPos = xOffset + ((j % cols) * (size+padding));
yPos = yOffset + ((j / cols) * (size+padding));
// Thumbs
patronen[j] = loadImage( j + ".png");
image(patronen[j], xPos, yPos);
// Check if thumb is clicked
if((mouseX >= xPos && mouseX <= xPos+size) &&
(mouseY >= yPos && mouseY <= yPos+size)){
if (mousePressed){
// grid patronen
xPos = 0;
yPos = 0;
// Loop pattern
while( yPos < height ){
while( xPos < width ){
patronen[j] = loadImage(j + "groot" + ".png");
selectedPatroon = patronen[j]
xPos += 500;
}
yPos +=500;
xPos = 0;
}
rect(xPos, yPos, size, size);
}
}
}
}
EDIT: The thing is, it works perfectly without
PImage selectedPatroon = patronen[patronen.length-1];
but then the looped pattern comes above all my others functions. And i want it to be under that.

You are creating an array at the top of your code then setting an image to the last element in the array, but you're not populating the array first.
PImage[] patronen = new PImage[7]; <<< Blank 7 element array.
int pLength = patronen.length;
PImage selectedPatroon = patronen[patronen.length-1];

To answer the questions you've put in the comments, you cannot populate an array of PImages with ints, those are different variable types. Try something like this in setup():
PImage patronen = new PImage[7];
for(int i = 0; i < patronen.length; i++){
patronen[i] = loadImage("image" + i + ".png"); // or whatever format your filenames are
}
The loadImage(String name) function returns a PImage, so you can insert it directly into your array. Just trying to insert the numbers won't work because the computer doesn't know that the numbers represent the filename without you telling it with loadImage().

Related

Blur filter in C results in only a slightly changed image

i am trying to make a blur filter in c that takes the neighboring pixels of the main pixel, takes the avarage of the rgb values and stores it in the temp array, them changes the image using the temp array values, it seems correct but it is not working as intended, giving an output of a very slightly blured image. I realy dont see my mistake and would be very thankful if someone helped, sorry if i made something horrible, started learning c last week.
i checked this post
Blurring an Image in c pixel by pixel - special cases
but i did not see were i went wrong.
im working with this data struct
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
void blur(int height, int width, RGBTRIPLE image[height][width])
{
// ints to use later
int j;
int p;
RGBTRIPLE temp[height][width];
for(int n = 0; n < height; n++) // loop to check every pixel
{
for(int k = 0; k < width; k++)
{
int widx = 3;
int hghtx = 3;
// conditionals for border cases
int y = 0;
if(n == 0)
{
p = 0;
hghtx = 2;
}
if(n == height - 1)
{
p = -1;
hghtx = 2;
}
if(k == 0)
{
j = 0;
widx = 2;
}
if(k == width - 1)
{
j = -1;
widx = 2;
}
for(int u = 0; u < hghtx; u++) // matrix of pixels around the main pixel using the conditionals gathered before
for(int i = 0; i < widx; i++)
if(y == 1) // takes the average of color and stores it in the RGB temp
{
temp[n][k].rgbtGreen = temp[n][k].rgbtGreen + image[n + p + u][k + j + i].rgbtGreen / (hghtx * widx);
temp[n][k].rgbtRed = temp[n][k].rgbtRed + image[n + p + u][k + j + i].rgbtRed / (hghtx * widx);
temp[n][k].rgbtBlue = temp[n][k].rgbtBlue + image[n + p + u][k + j + i].rgbtBlue / (hghtx * widx);
}
else // get first value of temp
{
temp[n][k].rgbtGreen = (image[n + p + u][k + j + i].rgbtGreen) / (hghtx * widx);
temp[n][k].rgbtRed = (image[n + p + u][k + j + i].rgbtRed) / (hghtx * widx);
temp[n][k].rgbtBlue = (image[n + p + u][k + j + i].rgbtBlue) / (hghtx * widx);
y++;
}
}
}
// changes the original image to the blured one
for(int n = 0; n < height; n++)
for(int k = 0; k < width; k++)
image[n][k] = temp[n][k];
}
I think it's a combination of things.
If the code worked the way you expect, you would be still doing a blur of just 3x3 pixels and that can be hardly noticeable, especially on large images (I'm pretty sure it will be unnoticeable on an image 4000x3000 pixels)
There are some problems with the code.
As #Fe2O3 says, at the end of the first line, widx will change to 2 and stay 2 for the rest of the image.
you are reading from temp[][] without initializing it. I think that if you compile that in release mode (not debug), temp[][] will contain random data and not all zeros as you probably expect. (as #WeatherWane pointed out)
The way you calculate the average of the pixels is weird. If you use a matrix 3x3 pixels, each pixel value shoud be divided by 9 in the final sum. But you divide the first pixel nine times by 2 (in effect doing /256), the second one eight times by 2 (so its pixel/128) etc. until the last one is divided by 2. So basically, it's mostly the value of the bottom right pixel.
also, since your RGB values are just bytes, you may want to divide them first and only then add them, because otherwise, you'll get overflows with wild results.
Try using a debugger to see the values you are actually calculating. It can be quite an eye opener :)

Triggering infinite animated objects

I would like to display, in Processing, one photo fading up and fading down over 15 seconds, with a second photo doing the same one second later, and another, etc, ad infinitum.
This example displays 15 objects, but they all start together:
PImage[] imgs = new PImage[42];
int Timer;
Pic[] pics = new Pic[15];
void setup() {
size(1000, 880);
for (int i = 0; i < pics.length; i++) {
pics[i] = new Pic(int(random(0, 29)), random(0, 800), random(0, height));
}
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
}
void draw() {
background(255);
for (int i = 0; i < pics.length; i++) {
pics[i].display();
}
}
class Pic {
float x;
float y;
int num;
int f = 0;
boolean change = true;
Pic(int tempNum, float tempX, float tempY) {
num = tempNum;
x = tempX;
y = tempY;
}
void display() {
imageMode(CENTER);
if (change)f++;
else f--;
if (f==0||f==555)change=!change;
tint(0, 153, 204, f);
image(imgs[num], x, y);
}
}
Thanks!!!
The main issue is you're updating/rendering all images all Pic instances at once. Perhaps you meant to display one at a time (one after the other).
There other sections that raise questions as well:
Timer is never used: it's a good idea to simplify/cleanup code as much as possible
f is used for both the tint alpha (0-255 range) and to fake a delay across multple frames (==555 check)
num is asigned to a random value which means potentially the same pic may be repeated (potentially even consecutively ?) making it hard to notice the effect
I recommend slowing down and breaking the problem down:
fade a single image in and out
determine when a fade in/out cycle is complete
increment a single index (so the next image can fade in and out)
Ideally you want to take the timing (15 seconds into account).
You can work out across how many frames you'd need to fade over 15 seconds. Processing's frameRate property can help with that:
numAlphaSteps = 15 * frameRate;
(e.g. at 60 fps that would be 15 * 60 = 900 frames)
That being said, it takes a few frames for frameRate to "warm up" and become stable. The safer option would be to call frameRate() passing the resired frames per second and reusing that number for the animation
The next step is to map each increment to an alpha value, as it needs to ramp up and back down. You could use a bit of arithmetic.
If you subtract half the number of total fade frames (e.g. 900 / 2 = 450) from each frame number you'd get a value that goes from -half the number of frames to half the number of frames. Here's a minimal sketch you can try out:
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
println("frame index", i, "ramp value", i - numFramesHalf);
}
Here's the same, visualised:
background(0);
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
int ramp = i - numFramesHalf;
println("frame index", i, "ramp value", ramp);
// visualise numbers
fill(0, 128, 0);
rect(i * 10, 50, 10, map(ramp, 0, 5, 0, 39));
fill(255);
text(i + "\n" + ramp, i * 10, height / 2);
}
(Feel free to change numFrames to 900, 10 is easier to see in console).
If you pass the subtraction result to abs() you'll get positive values:
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
println("frame index", i, "ramp value", abs(i - numFramesHalf));
}
and the visualisation:
background(0);
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i < numFrames; i++){
int ramp = abs(i - numFramesHalf);
println("frame index", i, "ramp value", ramp);
// visualise numbers
fill(0, 128, 0);
rect(i * 10, 0, 10, map(ramp, 0, 5, 0, 39));
fill(255);
text(i + "\n" + ramp, i * 10, height / 2);
}
If you look in Processing Console you should see values that resemble a linear ramp (e.g. large to 0 then back to large).
This is a range that can be easily remapped to a the 0 to 255 range, required for the alpha value, using map(yourValue, inputMinValue, inputMaxValue, outputMinValue, outputMaxValue).
Here's a sketch visualising the tint value going from 0 to 255 and back to 255:
size(255, 255);
int numFrames = 10;
int numFramesHalf = numFrames / 2;
for(int i = 0 ; i <= numFrames; i++){
int frameIndexToTint = abs(i - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
println("frame index", i, "ramp value", frameIndexToTint, "tint", tint);
rect((width / numFrames) * i, height, 1, -tint);
}
Now with these "ingredients" it should be possible to switch from a for loop draw():
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
void setup(){
size(255, 255);
}
void draw(){
// increment frame
frameIndex++;
// reset frame
if(frameIndex > numFrames){
frameIndex = 0;
println("fade transition complete");
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(tint);
fill(255 - tint);
text(String.format("frameIndex: %d\ntint: %.2f", frameIndex, tint), 10, 15);
}
Notice that using custom index for the transition frame index makes it easy to know when a transition is complete (so it can be reset): this is useful to also increment to the next image:
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
void setup(){
size(255, 255);
}
void draw(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
println("fade transition complete, next image: ", imageIndex);
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(tint);
fill(255 - tint);
text(String.format("frameIndex: %d\ntint: %.2f\nimageIndex: %d", frameIndex, tint, imageIndex), 10, 15);
}
These are the main ingredients for your program. You can easily swap the placeholder background drawing with your images:
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
PImage[] imgs = new PImage[42];
int[] randomImageIndices = new int[maxImages];
void setup(){
size(255, 255);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// pick random images
for (int i = 0; i < maxImages; i++) {
randomImageIndices[i] = int(random(0, 29));
}
}
void draw(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
println("fade transition complete, next image: ", imageIndex);
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(0);
PImage randomImage =imgs[randomImageIndices[imageIndex]];
tint(255, tint);
image(randomImage, 0, 0);
//debug info
fill(255);
text(String.format("frameIndex: %d\ntint: %.2f\nimageIndex: %d", frameIndex, tint, imageIndex), 10, 15);
}
The x, y position of the image isn't random, but that should be easy to replicated based on how the random image index is used.
Alternatively you can use a single random index and position that get's reset at the end of each transition:
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
PImage[] imgs = new PImage[42];
int randomImageIndex;
float randomX, randomY;
void setup(){
size(255, 255);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// pick random index
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
void draw(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
// reset random values
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
println("fade transition complete, next image: ", imageIndex);
}
// compute tint
int frameIndexToTint = abs(frameIndex - numFramesHalf);
float tint = map(frameIndexToTint, 0, numFramesHalf, 255, 0);
// visualise tint as background gray
background(0);
PImage randomImage =imgs[randomImageIndex];
tint(255, tint);
image(randomImage, randomX, randomY);
//debug info
fill(255);
text(String.format("frameIndex: %d\ntint: %.2f\nimageIndex: %d", frameIndex, tint, imageIndex), 10, 15);
}
And you can also encapsulate instructions grouped by functionality into functions (removing the redundant imageIndex since we're using a random index):
int numFrames = 180;
int numFramesHalf = numFrames / 2;
int frameIndex = 0;
int imageIndex = 0;
int maxImages = 15;
PImage[] imgs = new PImage[42];
int randomImageIndex;
float randomX, randomY;
void setup(){
size(255, 255);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// pick random index
randomizeImage();
}
void draw(){
updateFrameAndImageIndices();
background(0);
PImage randomImage =imgs[randomImageIndex];
tint(255, tintFromFrameIndex());
image(randomImage, randomX, randomY);
}
float tintFromFrameIndex(){
int frameIndexToTint = abs(frameIndex - numFramesHalf);
return map(frameIndexToTint, 0, numFramesHalf, 255, 0);
}
void updateFrameAndImageIndices(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// increment image index
imageIndex++;
// reset image index (if larger than total images to display)
if(imageIndex >= maxImages){
imageIndex = 0;
}
// reset random values
randomizeImage();
println("fade transition complete, next image: ", imageIndex);
}
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
If the goal of this coding excecise is to practice using classes, you can easily further encapsulate the image fade related functions and variables into a class:
PImage[] imgs = new PImage[42];
ImagesFader fader;
void setup(){
size(255, 255);
frameRate(60);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
// setup fader instance
// constructor args: PImage[] images, float transitionDurationSeconds, int frameRate
// use imgs as the images array, transition in and out within 1s per image at 60 frames per second
fader = new ImagesFader(imgs, 1.0, 60);
}
void draw(){
background(0);
fader.draw();
}
class ImagesFader{
int numFrames;
int numFramesHalf;
int frameIndex = 0;
PImage[] images;
int maxImages = 15;
int randomImageIndex;
float randomX, randomY;
ImagesFader(PImage[] images, float transitionDurationSeconds, int frameRate){
numFrames = (int)(frameRate * transitionDurationSeconds);
numFramesHalf = numFrames / 2;
println(numFrames);
this.images = images;
// safety check: ensure maxImage index isn't larger than the total number of images
maxImages = min(maxImages, images.length - 1);
// pick random index
randomizeImage();
}
void draw(){
updateFrameAndImageIndices();
PImage randomImage = imgs[randomImageIndex];
// isolate drawing style (so only the image fades, not everything in the sketch)
pushStyle();
tint(255, tintFromFrameIndex());
image(randomImage, randomX, randomY);
popStyle();
}
float tintFromFrameIndex(){
int frameIndexToTint = abs(frameIndex - numFramesHalf);
return map(frameIndexToTint, 0, numFramesHalf, 255, 0);
}
void updateFrameAndImageIndices(){
// increment frame
frameIndex++;
// reset frame (if larger than transition frames total)
if(frameIndex >= numFrames){
frameIndex = 0;
// randomize index and position
randomizeImage();
println("fade transition complete, next image: ", randomImageIndex);
}
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
}
If you're comfortable using Processing libraries, you can achieve the same with a tweening library like Ani:
import de.looksgood.ani.*;
import de.looksgood.ani.easing.*;
PImage[] imgs = new PImage[42];
float tintValue;
int randomImageIndex;
float randomX, randomY;
AniSequence fadeInOut;
void setup(){
size(255, 255);
frameRate(60);
// load images
for (int i = 0; i < imgs.length; i++) {
imgs[i] = loadImage(i+".png");
}
randomizeImage();
// Ani.init() must be called always first!
Ani.init(this);
// create a sequence
// dont forget to call beginSequence() and endSequence()
fadeInOut = new AniSequence(this);
fadeInOut.beginSequence();
// fade in
fadeInOut.add(Ani.to(this, 0.5, "tintValue", 255));
// fade out (and call sequenceEnd() when on completion)
fadeInOut.add(Ani.to(this, 0.5, "tintValue", 0, Ani.QUAD_OUT, "onEnd:sequenceEnd"));
fadeInOut.endSequence();
// start the whole sequence
fadeInOut.start();
}
void draw(){
background(0);
tint(255, tintValue);
image(imgs[randomImageIndex], randomX, randomY);
}
void sequenceEnd() {
randomizeImage();
fadeInOut.start();
}
void randomizeImage(){
randomImageIndex = int(random(0, 29));
randomX = random(width);
randomY = random(height);
}
Update Based on your comment regarding loading images, can you try this sketch ?
void setup(){
size(1000, 500);
textAlign(CENTER);
PImage[] images = loadImages("Data","png");
int w = 100;
int h = 100;
for(int i = 0; i < images.length; i++){
float x = i % 10 * w;
float y = i / 10 * h;
image(images[i], x, y, w, h);
text("["+i+"]",x + w / 2, y + h / 2);
}
}
PImage[] loadImages(String dir, String extension){
String[] files = listPaths(dir, "files", "extension=" + extension);
int numFiles = files.length;
PImage[] images = new PImage[numFiles];
for(int i = 0 ; i < numFiles; i++){
images[i] = loadImage(files[i]);
}
return images;
}
It should load images in the "Data" folder (as the comment mentions, not "data" which is commonly used in Processing). If "Data" is a typo, fix the path first (as Processing is key sensitive ("Data" != "data")). If the 50 images load correctly, it should display in a 10x5 grid at 100x100 px each (e.g. disregarding each image's aspect ratio). This should help test if the images load correctly. (Again, breaking the problem down to individual steps).

Draw an image from an array value p5.js

I am fairly new to p5.js, however I am trying to read a .txt file which contains the below text, and draw a picture depending on the value within the .txt file.
00000
20022
00222
22020
11111
I am currently stumped as to how to draw an image depending on the number in the array, as an example '1' would be grass. I have loaded the file in as a string using the following code: track = loadStrings("track1.txt");
I am trying to load it as a 5x5 'tile' if you will. Any help would be appreciated :)
I've used p5.Image to create a picture based on the pixels in the file.
This is a way of writing the code:
let track;
let colors;
let img;
function setup() {
createCanvas(100, 100);
track=loadStrings("track1.txt")
colors = [color(255,0,0),color(0,255,0),color(0,0,255)]
}
function draw() {
background(220);
img = createImage(track.length, track[0].length)
img.loadPixels();
for (let i = 0 ; i < track.length ; i++){
for (let j = 0 ; j < track.length ; j++){
img.set(i, j, colors[int(track[i][j])]);
}
}
img.updatePixels();
image(img, 50, 50);
}
Well you could probs split it up into arrays and also if you'd have some sort of seperator for colors, like: track1.txt: 10, 30, 255\n ... r, g, b\n .... Right now you would have to use the rgb rrrgggbbb
let colors = track.split("\n") // makes every new line into an array
for(let x = 0; x <= width; x ++) // "\n" = new line
for(let y = 0; y <= height; y ++){
let currentCol = []
for(let i = 0; i < 9; i += 3)
currentCol.push(
colors[x + y][0 + i] + // I'm really not sure about the: colors[x + y]...
colors[x + y][1 + i] +
colors[x + y][2 + i]
)
set(x, y, color(currentCol[0], currentCol[1], currentCol[2]))
}
I also made a function with a slightly different formula, which might work better, i am not sure though, but this is the actual formula to get from pixel array
function getColor(x, y, allColorsArr){
let _col = [] // current color, underscore not to accidentally clear your variable
for(let i = 0; i < 3; i ++)
_col.push(
allColorsArr[x + y * width][0 + i * 3] +
allColorsArr[x + y * width][1 + i * 3] +
allColorsArr[x + y * width][2 + i * 3]
)
return {
r: parseInt(_col[0], 10),
g: parseInt(_col[1], 10),
b: parseInt(_col[2], 10)
} // returning an object here just for the `.r`; `.g`; `.b`
} // you could do something like: let Colors = {red: 0, green: 1, blue: 2}
// col[Colors.red], col[Colors.green], col[Colors.blue] if you want
// example: let col = getColor(1, 0, track.split("\n"))
// example: stroke(col.r, col.g, col.b)
THERE IS MOST LIKELY IS A BETTER WAY TO DO THIS, but at least this works...

How to left pad a 2 dimensional byte array with leading zeros in C#

I have a 2 dimensional byte array of a bitmap pixel data that I need to send to a thermal printer using ESC/POS via comport. I can do this successfully. However, I need to shift the printed image to the right. Center justify, Right justify, HT, and all other ESC/POS commands have no effect due to the command used to print the bitmap (DC2 * r n [d1.....dn]).
I wish to left pad the array of bytes containing the bitmap in order to shift the printed image to the right. Below are my code lines to print bitmap
private void Print_Bipmap()
{
int x;
int y;
int i;
int RowBytes;
byte n;
Color Pixels;
byte[,] ImageArray = new byte[bitmap.Width, bitmap.Height];
// Calculate output size
RowBytes = (bitmap.Width + 7) / 8;
// Generate body of array
for (y = 0; y < bitmap.Height; y++)
{ // Each row...
for (x = 0; x < (bitmap.Width / 8); x++)
{ // Each 8-pixel block within row...
ImageArray[x, y] = 0;
for (n = 0; n < 8; n++)
{ // Each pixel within block...
Pixels = bitmap.GetPixel(x * 8 + n, y);
if (Pixels.GetBrightness() < 0.5)
{
ImageArray[x, y] += (byte)(1 << (7 - n));
}
}
}
}
comport_writeByte(18); //DC2
comport_writeByte(42); //*
comport_writeByte((byte)bitmap.Height); //r
comport_writeByte((byte)RowBytes); //n
for (y = 0; y < bitmap.Height; y++)
{
for (x = 0; x < RowBytes; x++)
{
comport_writeByte(ImageArray[x, y]); //[d1 ..... dn]
}
}
}
How do I left pad the 2 dimensional array (ImageArray[x, y])?
Many thanks in advance.

Using two Arrays in C/Gameboy programming

For a game in Gameboy programming, I am using four arrays called top, oldTop, bottom and oldBottom:
struct Point { int x, y; };
struct Rect { struct Point xx, yy; };
Rect top[size], oldTop[size];
Rect bottom[size], oldBottom[i];
where Rect is a struct made of two Struct Points, the top-left and the bottom right corner points.
The idea of the game is to have random-heighted blocks top-down from the ceiling and bottom-up from the floor.
It is similar to the copter-classic game. In my infinite while loop, I shift all of the rectangles down by one pixel using the following code
while (1)
{
for (int i = 0; i < size; i++)
{
//in Struct Rect, xx is the top-left corner point, and yy is the bottom right
top[i].xx.x--;
top[i].yy.x--;
bottom[i].xx.x--;
bottom[i].yy.x--;
if (top[i].xx.x < 0)
{
top[i].xx.x += 240;
top[i].yy.x += 240;
}
if (bottom[i].xx.x < 0)
{
bottom[i].xx.x += 240;
bottom[i].yy.x += 240;
}
}
for (int i = 0; i < size; i++)
{
drawRect(oldTop[i], colorBlack);
drawRect(oldBottom[i], colorBlack);
}
/*call delay function that wait for Vertical Blank*/
for(int i = 0; i < size; i++)
{
drawRect(top[i], colorGreen);
drawRect(bottom[i], colorGreen);
oldTop[i] = top[i];
oldBottom[i] = bottom[i];
}
}
The drawRect method uses DMA to draw the rectangle.
with this code, the code should display the rectangles like this: (drew this up in paint)
But the result I get is
What is odd is that if I don't draw the bottom row at all, then the top row draws fine. The result only messes up when I draw both. This is really weird because I think that the code should be working fine, and the code is not very complicated. Is there a specific reason this is happening, and is there a way to remedy this?
Thanks.
The code that I use to draw the rectangle looks like this:
void drawRect(int row, int col, int width, int height){
int i;
for (i=0; i<height; i++)
{
DMA[3].src = &color;
DMA[3].dst = videoBuffer + (row+r)*240 + col);
DMA[3].cnt = DMA_ON | DMA_FIXED_SOURCE | width;
}
}
Here's a debugging SSCCE (Short, Self-Contained, Correct Example) based on your code. There are assertions in this code that fire; it runs, but is known not to be correct. I've renamed bottom to btm and oldBottom to oldBtm so that the names are symmetric; it makes the code layout more systematic (but is otherwise immaterial).
#include <assert.h>
#include <stdio.h>
typedef struct Point { int x, y; } Point;
typedef struct Rect { struct Point xx, yy; } Rect;
enum { size = 2 };
typedef enum { colourGreen = 0, colourBlack = 1 } Colour;
/*ARGSUSED*/
static void drawRect(Rect r, Colour c)
{
printf(" (%3d)(%3d)", r.xx.x, r.yy.x);
}
int main(void)
{
Rect top[size], oldTop[size];
Rect btm[size], oldBtm[size];
int counter = 0;
for (int i = 0; i < size; i++)
{
top[i].xx.x = 240 - 4 * i;
top[i].xx.y = 0 + 10 + i;
top[i].yy.x = 240 - 14 * i;
top[i].yy.y = 0 + 20 + i;
btm[i].xx.x = 0 + 72 * i;
btm[i].xx.y = 0 + 10 * i;
btm[i].yy.x = 0 + 12 * i;
btm[i].yy.y = 0 + 20 * i;
oldTop[i] = top[i];
oldBtm[i] = btm[i];
}
while (1)
{
if (counter++ > 480) // Limit amount of output!
break;
for (int i = 0; i < size; i++)
{
//in Struct Rect, xx is the top-left corner point, and yy is the bottom right
top[i].xx.x--;
top[i].yy.x--;
btm[i].xx.x--;
btm[i].yy.x--;
if (top[i].xx.x < 0)
{
top[i].xx.x += 240;
top[i].yy.x += 240;
}
if (btm[i].xx.x < 0)
{
btm[i].xx.x += 240;
btm[i].yy.x += 240;
}
}
for (int i = 0; i < size; i++)
{
assert(top[i].xx.x >= 0 && top[i].yy.x >= 0);
assert(btm[i].xx.x >= 0 && btm[i].yy.x >= 0);
}
for (int i = 0; i < size; i++)
{
drawRect(oldTop[i], colourBlack);
drawRect(oldBtm[i], colourBlack);
}
/*call delay function that wait for Vertical Blank*/
for(int i = 0; i < size; i++)
{
drawRect(top[i], colourGreen);
drawRect(btm[i], colourGreen);
oldTop[i] = top[i];
oldBtm[i] = btm[i];
}
putchar('\n');
}
return(0);
}
As noted in a late comment, one big difference between this and your code is that oldBottom in your code is declared as:
Rect top[size], oldTop[size];
Rect bottom[size], oldBottom[i];
using the size i instead of size. This probably accounts for array overwriting issues you see.
There's a second problem though; the assertions in the loop in the middle fire:
(240)(240) ( 0)( 0) (236)(226) ( 72)( 12) (239)(239) (239)(239) (235)(225) ( 71)( 11)
(239)(239) (239)(239) (235)(225) ( 71)( 11) (238)(238) (238)(238) (234)(224) ( 70)( 10)
(238)(238) (238)(238) (234)(224) ( 70)( 10) (237)(237) (237)(237) (233)(223) ( 69)( 9)
(237)(237) (237)(237) (233)(223) ( 69)( 9) (236)(236) (236)(236) (232)(222) ( 68)( 8)
(236)(236) (236)(236) (232)(222) ( 68)( 8) (235)(235) (235)(235) (231)(221) ( 67)( 7)
(235)(235) (235)(235) (231)(221) ( 67)( 7) (234)(234) (234)(234) (230)(220) ( 66)( 6)
(234)(234) (234)(234) (230)(220) ( 66)( 6) (233)(233) (233)(233) (229)(219) ( 65)( 5)
(233)(233) (233)(233) (229)(219) ( 65)( 5) (232)(232) (232)(232) (228)(218) ( 64)( 4)
(232)(232) (232)(232) (228)(218) ( 64)( 4) (231)(231) (231)(231) (227)(217) ( 63)( 3)
(231)(231) (231)(231) (227)(217) ( 63)( 3) (230)(230) (230)(230) (226)(216) ( 62)( 2)
(230)(230) (230)(230) (226)(216) ( 62)( 2) (229)(229) (229)(229) (225)(215) ( 61)( 1)
(229)(229) (229)(229) (225)(215) ( 61)( 1) (228)(228) (228)(228) (224)(214) ( 60)( 0)
Assertion failed: (btm[i].xx.x >= 0 && btm[i].yy.x >= 0), function main, file video.c, line 63.
I think your 'not negative' checks should be revised to:
if (top[i].xx.x < 0)
top[i].xx.x += 240;
if (top[i].yy.x < 0)
top[i].yy.x += 240;
if (btm[i].xx.x < 0)
btm[i].xx.x += 240;
if (btm[i].yy.x < 0)
btm[i].yy.x += 240;
This stops anything going negative. However, it is perfectly plausible that you should simply be checking on the bottom-right x-coordinate (instead of the top-left coordinate) using the original block. Or the wraparound may need to be more complex altogether. That's for you to decipher. But I think that the odd displays occur because you were providing negative values where you didn't intend to and weren't supposed to.
The key points to note here are:
When you're debugging an algorithm, you don't have to use the normal display mechanisms.
When you're debugging, reduce loop sizes where you can (size == 2).
Printing just the relevant information (here, the x-coordinates) helped reduce the output.
Putting the counter code to limit the amount of output simplifies things.
If things are going wrong, look for patterns in what is going wrong early.
I had various versions of the drawRect() function before I got to the design shown, which works well on a wide screen (eg 120x65) terminal window.

Resources