C++ rendering shapes - c++

I'm trying to generate shapes within a specific area. the game i am making has a resolution of 1024x768 but the game board occupies only 768x768 in the centre of the screen.
Currently, i can get the shapes to randomly generate and not exceed the MAXIMUM_WIDTH and MAXIMUM_HEIGHT constraints. However, the shapes can still render too far left which is off the game board. I tried adding MINIMUM_WIDTH and MINUMUM_HEIGHT but i'm not sure where to apply this in the x= and y= stage
I've included the relevant code below.
What can i add/modify to this code to make the shapes be limited to the game board?
Thanks.
const size_t MaxShapes {5};
const unsigned int MaxScale {5};
const unsigned int MINIMUM_WIDTH = 128;
const unsigned int MAXIMUM_WIDTH = 896;
const unsigned int MINUMUM_HEIGHT = 0;
const unsigned int MAXIMUM_HEIGHT = 768;
bool PlayState::onCreate()
{
snakes_.push_back(new AISnake);
snakes_.back()->setPosition(Position(40,40));
snakes_.push_back(new PlayerSnake);
snakes_.back()->setPosition(Position(20,20));
double x, y;
for(unsigned shape = 0;shape < MaxShapes;shape++)
{
x = (double)(rand() % MAXIMUM_WIDTH);
y = (double)(rand() % MAXIMUM_HEIGHT);
shapes_.push_back(Triangle({x, y}));
}
return true;
}

You could try
x = (double)((rand() % (MAXIMUM_WIDTH - MINIMUM_WIDTH)) + MINIMUM_WIDTH);
y = (double)((rand() % (MAXIMUM_HEIGHT - MINIMUM_HEIGHT)) + MINIMUM_HEIGHT);
Say you want to find a random number between 5 and 15. The difference between 5 and 15 is 10. So you first find a random number between 0 and 10 and then add that to 5 to bring it back into the proper range (between 5 and 15).

Related

Tilegrid made of RectangleShape in SFML gives conversion error

I am learning C++ and want to get into graphics. I am using SFML, and am trying to make a snake game. I want to use rectangle shapes and update the position of each rectangle by referring to an array and factor of 40 (my tilesize). I believe I got the for loops right, but am struggling to use sf::setPosition. It gives me a conversion error. Here is my code:
#include <SFML\Graphics.hpp>
int main()
{
int xWindow = 1280; //Divided by 40 pixels, equals to a width of 32 tiles
int yWindow = 720; //Divided by 40 pixels, equals to a height of 18 tiles
float array[32][18] = { 0 };
sf::RenderWindow window(sf::VideoMode(xWindow, yWindow), "Title"); //32 & 18
while (window.isOpen())
{
////////Grid variables/////////
int xFactor = 32;
int yFactor = 18;
int size = 40;
////////Events////////
////////draw////////
window.clear();
for (int i = 0; i <= 31;i++)
{
for (int j = 0; j <= 17; j++)
{
sf::RectangleShape block(sf::Vector2f(size, size));
block.setFillColor(sf::Color::Blue);
block.setPosition(array[i * size][j * (size)]); //ERROR OCCURS HERE: cannot convert argument 1 from 'float' to 'const sf::Vector2f &'
window.draw(block);
}
}
///////Display//////
window.display();
}
}
I am thinking that setPosition only takes float or vector as input, but if I'm not mistaken you can't move through an array with anything other than integers?
How would set up a simple grid like this in SFML C++?
Thanks for any answers!
A position is 2 numbers, an x and y cordinate. array[i * size][j * (size)] is just one number in your 2d float array.
I would go for something like this instead
block.setPosition(i*size, j*size);

Grid based movement in Snake Game C++

I have basic knowledge of c++ and am trying to create a simple Snake game that will run on a 84 x 48 pixel LCD screen. The game works fine, but there is one thing I have been stuck on for a while, and I haven't found any help in any previous post:
so far, the movement of the snake is free, i.e. it moves pixel by pixel, meaning that, the snake being composed of 3 x 3 pixel squares, most of the times it doesn't automatically align with the fruit. I would like to implement a "grid system", so turn my 84 x 48 game space into a 28 x 16 grid in which the snake moves and eats the fruit without the player having to adjust its trajectory many times before getting the right alignment with the fruit.
Here's the part of my code in which I print the snake to the screen:
void Snake::head_init(int size)
{
_size = size;
_x = (GRIDX/2 - _size/2)*_size;
_y = (GRIDY/2 - _size/2)*_size;
printf("Snake initially at x = %i, y = %i\n", _x,_y);
}
void Snake::draw(N5110 &lcd)
{
lcd.drawRect(_x,_y,_size,_size, FILL_BLACK); // draw head
for(int k = 0; k < _tail_length; k++) {
lcd.drawRect(_tail_x[k],_tail_y[k],_size,_size, FILL_BLACK); // print tail
}
}
GRIDX = 28, GRIDY = 16, _size = 3
I tried to multiply _x and _y by the size of the snake when printing it, but this doesn't give me the result I am aiming to.
Also, I would like the fruit to spawn in the same 28 x 16 grid.
Here is how my fruit is printed for now:
void Fruit::init(int size)
{
_size = size;
srand(time(NULL)); // initialise random number generator for fruit positions
_x = rand() % 80 + 1; // generate a random x coordinate for fruit within the frame x range
_y = rand() % 43 + 1; // generate a random y coordinate for fruit within the frame y range
printf("Fruit initially at x = %i, y = %i \n", _x, _y); // print the random fruit coordinates over terminal
}
void Fruit::draw(N5110 &lcd)
{
lcd.drawSprite(_x,_y,3,3,(int *)fruit); // draw fruit at random position
}
Any help would be very appreciated

Pixel data unpacking to smaller sections

I'm trying to write a function that unpacks an image into separate quads. But for some reason the results are distorted (kinda stretched 45 degrees), so I must be reading the pixel array incorrectly, though I can't see the problem with my function...
The function takes 2 unsigned char arrays, "source" and "target" and two unsigned int values, the "width" and "height" of the source image. Width is dividable by 4, and height is dividable by 3 (both return the same value, because the texture is 600 * 450) so each face is 150*150 px. So the w/h values are correct. Then it also takes in 2 ints, "xIt" and "yIt" which determine the offset - which 150*150 block should be read.
Here's the function:
const unsigned int trgImgWidth = width / 4;
const unsigned int trgImgHeight = height / 3;
unsigned int trgBufferOffset = 0;
// Compute pixel offset to start reading from
unsigned int Yoffset = yIt * trgImgHeight * width * 3;
unsigned int Xoffset = xIt * trgImgWidth * 3;
for (unsigned int y = 0; y < trgImgHeight; y++)
{
unsigned int o = Yoffset + Xoffset; // Offset of current line of pixels
for (unsigned int x = 0; x < trgImgWidth * 3; x++) // for each pixel component (rgb) in the line
{
target[trgBufferOffset] = source[o + x];
trgBufferOffset++;
}
Yoffset += width * 3;
}
Anyone see where I might be going wrong here?

Drawing circle, OpenGL style

I have a 13 x 13 array of pixels, and I am using a function to draw a circle onto them. (The screen is 13 * 13, which may seem strange, but its an array of LED's so that explains it.)
unsigned char matrix[13][13];
const unsigned char ON = 0x01;
const unsigned char OFF = 0x00;
Here is the first implementation I thought up. (It's inefficient, which is a particular problem as this is an embedded systems project, 80 MHz processor.)
// Draw a circle
// mode is 'ON' or 'OFF'
inline void drawCircle(float rad, unsigned char mode)
{
for(int ix = 0; ix < 13; ++ ix)
{
for(int jx = 0; jx < 13; ++ jx)
{
float r; // Radial
float s; // Angular ("theta")
matrix_to_polar(ix, jx, &r, &s); // Converts polar coordinates
// specified by r and s, where
// s is the angle, to index coordinates
// specified by ix and jx.
// This function just converts to
// cartesian and then translates by 6.0.
if(r < rad)
{
matrix[ix][jx] = mode; // Turn pixel in matrix 'ON' or 'OFF'
}
}
}
}
I hope that's clear. It's pretty simple, but then I programmed it so I know how it's supposed to work. If you'd like more info / explanation then I can add some more code / comments.
It can be considered that drawing several circles, eg 4 to 6, is very slow... Hence I'm asking for advice on a more efficient algorithm to draw the circles.
EDIT: Managed to double the performance by making the following modification:
The function calling the drawing used to look like this:
for(;;)
{
clearAll(); // Clear matrix
for(int ix = 0; ix < 6; ++ ix)
{
rad[ix] += rad_incr_step;
drawRing(rad[ix], rad[ix] - rad_width);
}
if(rad[5] >= 7.0)
{
for(int ix = 0; ix < 6; ++ ix)
{
rad[ix] = rad_space_step * (float)(-ix);
}
}
writeAll(); // Write
}
I added the following check:
if(rad[ix] - rad_width < 7.0)
drawRing(rad[ix], rad[ix] - rad_width);
This increased the performance by a factor of about 2, but ideally I'd like to make the circle drawing more efficient to increase it further. This checks to see if the ring is completely outside of the screen.
EDIT 2: Similarly adding the reverse check increased performance further.
if(rad[ix] >= 0.0)
drawRing(rad[ix], rad[ix] - rad_width);
Performance is now pretty good, but again I have made no modifications to the actual drawing code of the circles and this is what I was intending to focus on with this question.
Edit 3: Matrix to polar:
inline void matrix_to_polar(int i, int j, float* r, float* s)
{
float x, y;
matrix_to_cartesian(i, j, &x, &y);
calcPolar(x, y, r, s);
}
inline void matrix_to_cartesian(int i, int j, float* x, float* y)
{
*x = getX(i);
*y = getY(j);
}
inline void calcPolar(float x, float y, float* r, float* s)
{
*r = sqrt(x * x + y * y);
*s = atan2(y, x);
}
inline float getX(int xc)
{
return (float(xc) - 6.0);
}
inline float getY(int yc)
{
return (float(yc) - 6.0);
}
In response to Clifford that's actually a lot of function calls if they are not inlined.
Edit 4: drawRing just draws 2 circles, firstly an outer circle with mode ON and then an inner circle with mode OFF. I am fairly confident that there is a more efficient method of drawing such a shape too, but that distracts from the question.
You're doing a lot of calculations that aren't really needed. For example, you're calculating the angle of the polar coordinates, but never use it. The square root can also easily be avoided by comparing the square of the values.
Without doing anything fancy, something like this should be a good start:
int intRad = (int)rad;
int intRadSqr = (int)(rad * rad);
for (int ix = 0; ix <= intRad; ++ix)
{
for (int jx = 0; jx <= intRad; ++jx)
{
if (ix * ix + jx * jx <= radSqr)
{
matrix[6 - ix][6 - jx] = mode;
matrix[6 - ix][6 + jx] = mode;
matrix[6 + ix][6 - jx] = mode;
matrix[6 + ix][6 + jx] = mode;
}
}
}
This does all the math in integer format, and takes advantage of the circle symmetry.
Variation of the above, based on feedback in the comments:
int intRad = (int)rad;
int intRadSqr = (int)(rad * rad);
for (int ix = 0; ix <= intRad; ++ix)
{
for (int jx = 0; ix * ix + jx * jx <= radSqr; ++jx)
{
matrix[6 - ix][6 - jx] = mode;
matrix[6 - ix][6 + jx] = mode;
matrix[6 + ix][6 - jx] = mode;
matrix[6 + ix][6 + jx] = mode;
}
}
Don't underestimate the cost of even basic arithmetic using floating point on a processor with no FPU. It seems unlikely that floating point is necessary, but the details of its use are hidden in your matrix_to_polar() implementation.
Your current implementation considers every pixel as a candidate - that is also unnecessary.
Using the equation y = cy ± √[rad2 - (x-cx)2] where cx, cy is the centre (7, 7 in this case), and a suitable integer square root implementation, the circle can be drawn thus:
void drawCircle( int rad, unsigned char mode )
{
int r2 = rad * rad ;
for( int x = 7 - rad; x <= 7 + rad; x++ )
{
int dx = x - 7 ;
int dy = isqrt( r2 - dx * dx ) ;
matrix[x][7 - dy] = mode ;
matrix[x][7 + dy] = mode ;
}
}
In my test I used the isqrt() below based on code from here, but given that the maximum r2 necessary is 169 (132, you could implement a 16 or even 8 bit optimised version if necessary. If your processor is 32 bit, this is probably fine.
uint32_t isqrt(uint32_t n)
{
uint32_t root = 0, bit, trial;
bit = (n >= 0x10000) ? 1<<30 : 1<<14;
do
{
trial = root+bit;
if (n >= trial)
{
n -= trial;
root = trial+bit;
}
root >>= 1;
bit >>= 2;
} while (bit);
return root;
}
All that said, on such a low resolution device, you will probably get better quality circles and faster performance by hand generating bitmap lookup tables for each radius required. If memory is an issue, then a single circle needs only 7 bytes to describe a 7 x 7 quadrant that you can reflect to all three quadrants, or for greater performance you could use 7 x 16 bit words to describe a semi-circle (since reversing bit order is more expensive than reversing array access - unless you are using an ARM Cortex-M with bit-banding). Using semi-circle look-ups, 13 circles would need 13 x 7 x 2 bytes (182 bytes), quadrant look-ups would be 7 x 8 x 13 (91 bytes) - you may find that is fewer bytes that the code space required to calculate the circles.
For a slow embedded device with only a 13x13 element display, you should really just make a look-up table. For example:
struct ComputedCircle
{
float rMax;
char col[13][2];
};
Where the draw routine uses rMax to determine which LUT element to use. For example, if you have 2 elements with one rMax = 1.4f, the other = 1.7f, then any radius between 1.4f and 1.7f will use that entry.
The column elements would specify zero, one, or two line segments per row, which can be encoded in the lower and upper 4 bits of each char. -1 can be used as a sentinel value for nothing-at-this-row. It is up to you how many look-up table entries to use, but with a 13x13 grid you should be able to encode every possible outcome of pixels with well under 100 entries, and a reasonable approximation using only 10 or so. You can also trade off compression for draw speed as well, e.g. putting the col[13][2] matrix in a flat list and encoding the number of rows defined.
I would accept MooseBoy's answer if only he explained the method he proposes better. Here's my take on the lookup table approach.
Solve it with a lookup table
The 13x13 display is quite small, and if you only need circles which are fully visible within this pixel count, you will get around with a quite small table. Even if you need larger circles, it should be still better than any algorithmic way if you need it to be fast (and have the ROM to store it).
How to do it
You basically need to define how each possible circle looks like on the 13x13 display. It is not sufficient to just produce snapshots for the 13x13 display, as it is likely you would like to plot the circles at arbitrary positions. My take for a table entry would look like this:
struct circle_entry_s{
unsigned int diameter;
unsigned int offset;
};
The entry would map a given diameter in pixels to offsets in a large byte table containing the shape of the circles. For example for diameter 9, the byte sequence would look like this:
0x1CU, 0x00U, /* 000111000 */
0x63U, 0x00U, /* 011000110 */
0x41U, 0x00U, /* 010000010 */
0x80U, 0x80U, /* 100000001 */
0x80U, 0x80U, /* 100000001 */
0x80U, 0x80U, /* 100000001 */
0x41U, 0x00U, /* 010000010 */
0x63U, 0x00U, /* 011000110 */
0x1CU, 0x00U, /* 000111000 */
The diameter specifies how many bytes of the table belong to the circle: one row of pixels are generated from (diameter + 7) >> 3 bytes, and the number of rows correspond to the diameter. The output code of these can be made quite fast, while the lookup table is sufficiently compact to get even larger than the 13x13 display circles defined in it if needed.
Note that defining circles this way for odd and even diameters may or may not appeal you when output by a centre location. The odd diameter circles will appear to have a centre in the "middle" of a pixel, while the even diameter circles will appear to have their centre on the "corner" of a pixel.
You may also find it nice later to refine the overall method so having multiple circles of different apparent sizes, but having the same pixel radius. Depends on what is your goal: if you want some kind of smooth animation, you may get there eventually.
Algorithmic solutions I think mostly will perform poorly here, since with this limited display surface really every pixel's state counts for the appearance.

C++AMP Computing gradient using texture on a 16 bit image

I am working with depth images retrieved from kinect which are 16 bits. I found some difficulties on making my own filters due to the index or the size of the images.
I am working with Textures because allows to work with any bit size of images.
So, I am trying to compute an easy gradient to understand what is wrong or why it doesn't work as I expected.
You can see that there is something wrong when I use y dir.
For x:
For y:
That's my code:
typedef concurrency::graphics::texture<unsigned int, 2> TextureData;
typedef concurrency::graphics::texture_view<unsigned int, 2> Texture
cv::Mat image = cv::imread("Depth247.tiff", CV_LOAD_IMAGE_ANYDEPTH);
//just a copy from another image
cv::Mat image2(image.clone() );
concurrency::extent<2> imageSize(640, 480);
int bits = 16;
const unsigned int nBytes = imageSize.size() * 2; // 614400
{
uchar* data = image.data;
// Result data
TextureData texDataD(imageSize, bits);
Texture texR(texDataD);
parallel_for_each(
imageSize,
[=](concurrency::index<2> idx) restrict(amp)
{
int x = idx[0];
int y = idx[1];
// 65535 is the maxium value that can take a pixel with 16 bits (2^16 - 1)
int valX = (x / (float)imageSize[0]) * 65535;
int valY = (y / (float)imageSize[1]) * 65535;
texR.set(idx, valX);
});
//concurrency::graphics::copy(texR, image2.data, imageSize.size() *(bits / 8u));
concurrency::graphics::copy_async(texR, image2.data, imageSize.size() *(bits) );
cv::imshow("result", image2);
cv::waitKey(50);
}
Any help will be very appreciated.
Your indexes are swapped in two places.
int x = idx[0];
int y = idx[1];
Remember that C++AMP uses row-major indices for arrays. Thus idx[0] refers to row, y axis. This is why the picture you have for "For x" looks like what I would expect for texR.set(idx, valY).
Similarly the extent of image is also using swapped values.
int valX = (x / (float)imageSize[0]) * 65535;
int valY = (y / (float)imageSize[1]) * 65535;
Here imageSize[0] refers to the number of columns (the y value) not the number of rows.
I'm not familiar with OpenCV but I'm assuming that it also uses a row major format for cv::Mat. It might invert the y axis with 0, 0 top-left not bottom-left. The Kinect data may do similar things but again, it's row major.
There may be other places in your code that have the same issue but I think if you double check how you are using index and extent you should be able to fix this.