Applying texture to array of sprites(C++, SFML, tmxlite) - c++

I'm having some difficulty applying a texture to a sprite array. I'm trying to apply the same texture to all, so that I can later setTextRect to decide which part of the texture is used as a tile in my game.
The declaration of the sprite array is in a different class and declared as follows:
sf::Sprite tileSprites[30][40]
Going line by line and debugging the stumbling block is the for loop. The response from the window is just to close and crash out with no errors.
The game crashes once the line where I try to apply the texture.
tileSprites[idx][idy].setTexture(tileMap);
std::cout << "Creating Map... \n";
// load the image to be used as map/the spritesheet.
if (!tileMap.loadFromFile("Data/Maps/tilemap.png"))
{
std::cout << "Tilemap PNG did not load";
}
//load the generated tilemap
if(!map.load("Data/Maps/test_map.tmx"))
{
std::cout << "TMX map file failed to load";
}
// access the layers in the map
const auto& layers = map.getLayers();
const auto layer = layers[0]->getLayerAs<tmx::TileLayer>();
const auto tiles = layer.getTiles();
int idx = 0;
int idy = 0;
for (int j = 0; j < tiles.size(); ++j)
{
idx = j / 30;
idy = j % 30;
tileSprites[idx][idy].setTexture(tileMap); // <-
}
std::cout << tiles.size();
}
Any advice would be really appreciated.

Related

Laggy Output to Console

I have been trying to make asteroids in the console, I know that the console isn't an ideal way to do this, but I wanted to challenge myself.
The problem I am having is with printing to the screen. At first, my screen was flickering because I wasn't updating certain screen parts and instead redrawing every frame by appending the whole array to a string and outputting that string.
So I changed my code to do that, but my current problem now is that the fps of my game is really low because I can't batch call it to one cout function.
To print my code to the screen I have a 2d array of characters with width and height as its size. Then I copy the array, change the output, and compare it to the previous output to see if the pixel needs to be changed, then change it.
Here is my draw function
void draw() {
char prevOutput[ArrayBorder][ArrayBorder];
copyOutput(outputBuffer, prevOutput);
innitOutput();
plotPolygons();
for (int y = 0; y < GameBorder; y++) {
for (int x = 0; x < GameBorder; x++) {
if (outputBuffer[x][y] == prevOutput[x][y]) {continue;}
setCursorPosition(x, y);
cout << outputBuffer[x][y];
}
}
cout.flush();
}
Here is my previous draw function
void draw() {
innitOutput();
plotPolygons();
system("CLS");
string output = "";
for (int y = 0; y < GameBorder; y++) {
for (int x = 0; x < GameBorder; x++) {
output += outputBuffer[x][y];
}
output += "\n";
}
cout << output;
}

How do you parallelize the flipping of image with Pthreads?

I'm new to Pthreads and c++ and trying to parallelize an image flipping program. Obviously it isnt working. I'm told I need to port some code from an Image class but not really sure what porting means. I just copied and pasted the code but I guess that's wrong.
I get the general idea. allocate the workload, intitialize the threads, create the threads, join the threads and define a callback function.
I'm not totally sure what the cells_per_thread should be. I'm pretty sure it should be the image width * height / threads. Does that seem correct?
I'm getting multiple errors when compiling with cmake.
its saying m_thread_number, getWidth, getHeight, getPixel, temp are not define in the scope. I assume thats because the Image class code isn't ported?
PthreadImage.cxx
//Declare a callabck fucntion for Horizontal flip
void* H_flip_callback_function(void* aThreadData);
PthreadImage PthreadImage::flipHorizontally() const
{
if (m_thread_number == 0 || m_thread_number == 1)
{
return PthreadImage(Image::flipHorizontally(), m_thread_number);
}
else
{
PthreadImage temp(getWidth(), getHeight(), m_thread_number);
//Workload allocation
//Create a vector of type ThreadData whcih is constructed at the top of the class under Struct ThreadData. Pass in the number of threads.
vector<ThreadData> p_thread_data(m_thread_number);
//create an integer to hold the last element. inizialize it as -1.
int last_element = -1;
//create an unsigned int to hold how many cells we need per thread. For the image we want the width and height divided by the number of threads.
unsigned int cells_per_thread = getHeight() * getWidth() / m_thread_number;
//Next create a variable to hold the remainder of the sum.
unsigned int remainder = getHeight() * getWidth() % m_thread_number;
//print the number of cells per thread to the console
cout << "Default number for cells per thread: " << cells_per_thread << endl;
//inizialize the threads with a for loop to interate through each thread and populate it
for (int i = 0; i < m_thread_number; i++)
{
//thread ids correspond with the for loop index values.
p_thread_data[i].thread_id = i;
//start is last element + 1 i.e -1 + 1 start = 0.
p_thread_data[i].start_id = ++last_element;
p_thread_data[i].end_id = last_element + cells_per_thread - 1;
p_thread_data[i].input = this;
p_thread_data[i].output = &temp;
//if the remainder is > thats 0 add 1 to the end them remove 1 remainder.
if (remainder > 0)
{
p_thread_data[i].end_id++;
--remainder;
}
//make the last element not = -1 but = the end of the threads.
last_element = p_thread_data[i].end_id;
//print to console what number then thread start and end on
cout << "Thread[" << i << "] starts with " << p_thread_data[i].start_id << " and stops on " << p_thread_data[i].end_id << endl;
}
//create the threads with antoher for loop
for (int i = 0; i < m_thread_number; i++)
{
pthread_create(&p_thread_data[i].thread_id, NULL, H_flip_callback_function, &p_thread_data[i]);
}
//Wait for each thread to complete;
for (int i = 0; i < m_thread_number; i++)
{
pthread_join(p_thread_data[i].thread_id, NULL);
}
return temp;
}
}
Callback function
//Define the callabck fucntion for Horizontal flip
void* H_flip_callback_function(void* aThreadData)
{
//convert void to Thread data
ThreadData* p_thread_data = static_cast<ThreadData*>(aThreadData);
int tempHeight = temp(getHeight());
int tempWidth = temp(getWidth());
for (int i = p_thread_data->start_id; i <= p_thread_data->end_id; i++)
{
// Process every row of the image
for (unsigned int j = 0; j < m_height; ++j)
{
// Process every column of the image
for (unsigned int i = 0; i < m_width / 2; ++i)
{
(*(p_thread_data->output))( i, j) = getPixel(m_width - i - 1, j);
(*(p_thread_data->output))(m_width - i - 1, j) = getPixel( i, j);
}
}
}
}
Image class
#include <sstream> // Header file for stringstream
#include <fstream> // Header file for filestream
#include <algorithm> // Header file for min/max/fill
#include <numeric> // Header file for accumulate
#include <cmath> // Header file for abs and pow
#include <vector>
#include "Image.h"
//-----------------
Image::Image():
//-----------------
m_width(0),
m_height(0)
//-----------------
{}
//----------------------------------
Image::Image(const Image& anImage):
//----------------------------------
m_width(anImage.m_width),
m_height(anImage.m_height),
m_p_image(anImage.m_p_image)
//----------------------------------
Image class code to be ported
//-----------------------------------
Image Image::flipHorizontally() const
//-----------------------------------
{
// Create an image of the right size
Image temp(getWidth(), getHeight());
// Process every row of the image
for (unsigned int j = 0; j < m_height; ++j)
{
// Process every column of the image
for (unsigned int i = 0; i < tempWidth / 2; ++i)
{
temp(i, j) = getPixel(tempWidth - i - 1, j);
temp(tempWidth - i - 1, j) = getPixel(i, j);
}
}
return 0;
}
I feel like its pretty close. Any help greatly appreciated!
EDIT
Ok, so this is the correct code for anyone wasting their time on this.
There was obviously a fair few things wrong.
I don't know why there was 3 for loops. There should be 2. 1 for Rows and 1 for columns.
The cells_per_thread should be pixels_per_thread and rows/threads as #Larry B suggested not ALL the pixels per thread.
You can use -> to get members of a pointer i.e setPixel(),getPixel` etc. Who knew that!?
There was a data structure that was pretty inportant for you guys but I forgot.
struct ThreadData
{
pthread_t thread_id;
unsigned int start_id;
unsigned int end_id;
const Image* input;
Image* output;
};
Correct Callback
void* H_flip_callback_function(void* aThreadData)
{
//convert void to Thread data
ThreadData* p_thread_data = static_cast<ThreadData*>(aThreadData);
int width = p_thread_data->input->getWidth();
// Process every row of the image
for (unsigned int j = p_thread_data->start_id; j <=p_thread_data->end_id; ++j)
}
// Process every column of the image
for (unsigned int i = 0; i < width / 2; ++i)
{
p_thread_data->output->setPixel(i,j, p_thread_data->input->getPixel(width - i - 1, j));
p_thread_data->output->setPixel(width - i - 1, j, p_thread_data->input->getPixel(i, j));
}
}
return 0;
}
So now this code compiles and flips.
Thanks!
The general strategy for porting single threaded code to a multi-thread version is essentially rewriting the existing code to divide the work into self contained units of work that you can hand off to a thread for execution.
With that in mind, I don't agree with your implementation of H_flip_callback_function:
void* H_flip_callback_function(void* aThreadData)
{
//convert void to Thread data
ThreadData* p_thread_data = static_cast<ThreadData*>(aThreadData);
// Create an image of the right size
PthreadImage temp(getWidth(), getHeight(), m_thread_number);
int tempHeight = temp(getHeight());
int tempWidth = temp(getWidth());
for (int i = p_thread_data->start_id; i <= p_thread_data->end_id; i++)
{
// Process every row of the image
for (unsigned int j = 0; j < tempHeight; ++j)
{
// Process every column of the image
for (unsigned int i = 0; i < tempWidth / 2; ++i)
{
temp(i, j) = getPixel(tempWidth - i - 1, j);
temp(tempWidth - i - 1, j) = getPixel(i, j);
}
}
}
}
At face value, it looks like all your threads will be operating on the whole image. If this is the case, there is no real difference between your single and multi-thread version as you're just doing the same work multiple times in the multi-thread version.
I would argue that the smallest self contained unit of work would be to horizontally flip a single row of the image. However, if you have less threads than the number of rows, then you could allocate (Num rows / Num threads) to each thread. Each thread would then flip the rows assigned to it and the main thread would collect the results and assemble the final image.
With regards to your build warnings and errors, you'll have to provide the complete source code, build settings, environment, etc..

Extra sprite spawning when the enemies are redrawn SFML

I am making a game in sfml and at the moment when all of the enemies die. They are set to respawn however when this is happening they are respawning with one extra sprite than before.
The code for loading in the sprites is
unsigned int orcNumber = 5;
for (int i = 0; i < orcNumber; i++)
{
SpriteVector.push_back(ogreSprite);
SpriteVector[i].setPosition(spawnPointX[i], spawnPointY[i]);
}
The code for removing the enemies if they are offscreen or shot is similar to below using erase.
for (unsigned j = 0; j < SpriteVector.size(); j++)
{
if (this->SpriteVector[j].getPosition().x < 0 - 80 )
{
//this succesfully removes the object from the vector
SpriteVector.erase(SpriteVector.begin() + j);
std::cout << "Container size..." << SpriteVector.size() << "\n";
}
}
The statement for redrawing them is:
unsigned int orcNumberRespawn = 5;
if (SpriteVector.size() <= 1)
{
for (int i = 0; i < orcNumberRespawn; i++)
{
SpriteVector.push_back(ogreSprite);
SpriteVector[i].setPosition(spawnPointX[i], spawnPointY[i]);
}
}
window.draw(SpriteVector[i]);
Can anyone identify why when the sprites need to be redrawn it draws with + 1 sprite everytime?
The issue was with a loop outside of these vector loops.

Weird QImage compare result

I want to run a few unit tests on my OpenGL application. Which cause me a few issue in the past (OpenGL draw difference between 2 computers) but now I know what I can and cannot do.
Here's a little test I wrote to check the rendering:
QImage display(grabFrameBuffer());
QImage wanted(PATH_TO_RESSOURCES + "/file_010.bmp");
int Qimage_width = display.width();
int Qimage_height = display.height();
for(int i = 1; i < Qimage_width; i++) {
for(int j = 1; j < Qimage_height; j++) {
if(QColor(display.pixel(i, j)).name() != QColor(wanted.pixel(i, j)).name()) {
qDebug() << "different pixel detected" << i << j;
}
}
}
QVERIFY(wanted == display);
The QVERIFY() fails but the message "different pixel detected" << i << j is never shown.
If I compare the files with Photoshop (see photo.stackexchange), I can't find any different pixel. I'm kind of lost.
Edit : I'm using Qt 5.2 and if I change manually one pixel on file_010.bmp the error message "different pixel detected" << i << j is displayed.
The QImage equality operator will report that two QImage instances are different if the images have different formats, different sizes and/or different contents. For the benefit of others that might have trouble understanding why two QImage instances are different, the following function prints out what the differences are (though it may generate a lot of output if there are a lot of differing pixels):
void displayDifferencesInImages(const QImage& image1, const QImage& image2)
{
if (image1 == image2)
{
qDebug("Images are identical");
return;
}
qDebug("Found the following differences:");
if (image1.size() != image2.size())
{
qDebug(" - Image sizes are different (%dx%d vs. %dx%d)",
image1.width(), image1.height(),
image2.width(), image2.height());
}
if (image1.format() != image2.format())
{
qDebug(" - Image formats are different (%d vs. %d)",
static_cast<int>(image1.format()),
static_cast<int>(image2.format()));
}
int smallestWidth = qMin(image1.width(), image2.width());
int smallestHeight = qMin(image1.height(), image2.height());
for (int i=0; i<smallestWidth; ++i)
{
for (int j=0; j<smallestHeight; ++j)
{
if (image1.pixel(i, j) != image2.pixel(i, j))
{
qDebug(" - Image pixel (%d, %d) is different (%x vs. %x)",
i, j, image1.pixel(i, j), image2.pixel(i, j));
}
}
}
}

For loop for reading strings from a file into a 3D array

I'm having a problem with one of my functions, I'm working on a simple tile map editor, and I'm trying to implement a 3D array to keep track of tiles (x,y, layer). Before this I had a 1D array where all the tiles were just listed sequencially:
bool Map::OnLoad(char* File) {
TileList.clear();
FILE* FileHandle = fopen(File, "r");
if(FileHandle == NULL) {
return false;
}
for(int Y = 0;Y < MAP_HEIGHT;Y++) {
for(int X = 0;X < MAP_WIDTH;X++) {
Tile tempTile;
fscanf(FileHandle, "%d:%d ", &tempTile.TileID, &tempTile.TilePassage);
TileList.push_back(tempTile);
}
fscanf(FileHandle, "\n");
}
fclose(FileHandle);
return true;
}
This basically read strings from the file which looked like:
2:1 1:0 3:2...
Where the first number states the tileID and the second one states the Tile passability. The above function works. My 3D arrays are also correctly constructed, I tested them with simple assignments and calling values out of it. The function that gives me problems is the following (please note that the number 2 i.e. OnLoad2() was added so I can keep the old variables and the function untouched until the prototype is working):
bool Map::OnLoad2(char* File) {
TileList2.clear();
FILE* FileHandle2 = fopen(File, "r");
if(FileHandle2 == NULL) {
return false;
}
for(int Y = 0;Y < MAP_HEIGHT;Y++) {
for(int X = 0;X < MAP_WIDTH;X++) {
Tile tempTile;
fscanf(FileHandle2, "%d:%d ", &tempTile.TileID, &tempTile.TilePassage);
TileList2[X][Y][0] = tempTile;
}
fscanf(FileHandle2, "\n");
}
fclose(FileHandle2);
return true;
}
While this function doesn't trigger the compiler to report any errors, as soon as the application starts, it freezes up and crashes. For additional information MAP_WIDTH and MAP_HEIGHT are set to 40 each and the 3D array was constructed like this:
TileList2.resize(MAP_HEIGHT);
for (int i = 0; i < MAP_HEIGHT; ++i) {
TileList2[i].resize(MAP_WIDTH);
for (int j = 0; j < MAP_WIDTH; ++j)
TileList2[i][j].resize(3);
}
I would appreciate it if you could point me out what do I need to fix, as far as I know I must have messed up the for loop structure, as the 3D array initializes and works properly. Thank you for your help!
TileList2.clear();
This line reinitializes TileList2, so it is back to a zero-length vector. Delete that line, and you will probably be okay.