SFML - Cannot modify object in window - c++

I am new to SFML and C++ in general.
I am building the Conway's Game of life for a school project.
As base objects for my grid, I have Squares (which are sf::RectangleShape as for base).
The grid is a std::vector<std::vector<Square>> (vector of vectors of Squares).
What I am trying to do at the moment is to change the color of a square when I hover over it with the cursor.
My way of doing it (see code below):
I get the position of cursor when I move it
I iterate through my matrix and check for each square if cursor's position is in the square's boundaries.
When the square under the cursor is found, I want to change its color (.setFillColor(...)).
Point 3 does not work I can't understand why. This is the function "mouseHover" in the code below.
Can you see what is wrong?
int main()
{
int width;
int height;
int numberSquareWidth = 15;
int numberSquareHeight = 15;
int squareSize = 20;
int offset = 1;
initializeWindowGridValues(width, height, numberSquareWidth, numberSquareHeight, squareSize, offset);
sf::RenderWindow window(sf::VideoMode(width, height), "Stephan's Game Of Life!");
std::vector<std::vector<Square>> matrix(numberSquareWidth, std::vector<Square>(numberSquareHeight));
initiatlizeGrid(numberSquareWidth, numberSquareHeight, squareSize, offset, matrix);
sf::Vector2i cursorPos;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::MouseMoved)
{
cursorPos = sf::Mouse::getPosition(window);
}
}
mouseHover(matrix, cursorPos, squareSize, offset); // Problem here
window.clear(sf::Color::Black);
drawGrid(window, matrix);
window.display();
}
return 0;
}
void mouseHover(std::vector<std::vector<Square>> &matrix, const sf::Vector2i &cursorPos, const int &squareSize, const int &offset)
{
int rowIndex = floor((cursorPos.x - (offset * floor(cursorPos.x / squareSize))) / squareSize);
int colIndex = floor((cursorPos.y - (offset * floor(cursorPos.y / squareSize))) / squareSize);
matrix[rowIndex][colIndex].setFillColor(sf::Color::Blue); // This does not happen.
}
void drawGrid(sf::RenderWindow &window, const std::vector<std::vector<Square>> &matrix)
{
for (const auto &vector : matrix)
{
for (const auto &square : vector)
{
window.draw(square);
}
}
}
void initiatlizeGrid(const int &numberSquareWidth, const int &numberSquareHeight, const int &squareSize, const int &offset, std::vector<std::vector<Square>> &matrix)
{
int previousY = 0;
for (size_t row = 0; row < numberSquareWidth; row++)
{
int offsetv;
if (row == 0)
{
offsetv = 0;
}
else
{
offsetv = offset;
}
int previousX = 0;
for (size_t col = 0; col < numberSquareHeight; col++)
{
int offseth;
if (col == 0)
{
offseth = 0;
}
else
{
offseth = offset;
}
Square square(squareSize);
square.setPosition(previousX + offseth, previousY + offsetv);
matrix[row][col] = square;
previousX = previousX + squareSize + offseth;
}
previousY = previousY + squareSize + offsetv;
}
}
void initializeWindowGridValues(int &width, int &height, int &nuberSquareWidth, int &nuberSquareHeight, int &squareSize, const int &offset)
{
if (nuberSquareWidth * squareSize + offset * (nuberSquareWidth - 1) > 1800 || nuberSquareHeight * squareSize + offset * (nuberSquareHeight - 1) > 900)
{
nuberSquareWidth = floor(1600 / squareSize);
nuberSquareHeight = floor(900 / squareSize);
width = ceil(nuberSquareWidth * squareSize + offset * (nuberSquareWidth - 1));
height = ceil(nuberSquareHeight * squareSize + offset * (nuberSquareHeight - 1));
}
else if (nuberSquareWidth < 5 || nuberSquareHeight < 5)
{
nuberSquareWidth = 5;
nuberSquareHeight = 5;
width = ceil(nuberSquareWidth * squareSize + offset * (nuberSquareWidth - 1));
height = ceil(nuberSquareHeight * squareSize + offset * (nuberSquareHeight - 1));
}
else
{
width = ceil(nuberSquareWidth * squareSize + offset * (nuberSquareWidth - 1));
height = ceil(nuberSquareHeight * squareSize + offset * (nuberSquareHeight - 1));
}
}

The problem was that I have both inherited the RectangleShape (my square IS A RectangleShape) and made a RectangleShape (square) a member of myclass. When I modify data, I modify class member variables, but inside the draw method I draw the other rectangle.
I removed the class member RectangleShape and continue from here.

Related

How to fill sf::VertexArray of sf::TriangleStrip with color?

I would like to increase the drawing performance by using a single sf::VertexArray to display thousands of circles. To make sure it works, I wrote this example:
#include <SFML/Graphics.hpp>
#include <iostream>
#define WIDTH 100
#define HEIGHT 100
int main() {
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "RTREE",
sf::Style::Close);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
sf::CircleShape circle(50);
circle.setPosition(100,100);
size_t count = circle.getPointCount();
sf::VertexArray objects(sf::TriangleStrip, count);
for (int i = 0; i < count; i++) {
objects.append(circle.getPoint(i));
}
for (int i = 0; i < objects.getVertexCount(); i++) {
objects[i].color = sf::Color::Blue;
}
window.clear();
window.draw(objects);
window.display();
}
}
However, the color only applies to the line, not the fill:
Is it possible to fill the shape with a single color?
You are right, displaying more than 1000 circles with a window.draw between each of them result in poor performances. The vertexArray is indeed a good solution.
You used sf::TriangleStrip which does not work as you expected. Your verticles are indeed painted, but they are only on the edge of the circle. You need to use either sf::TriangleFan or sf::Triangles if you want more than one circle per array.
Here an example. I was able to display 513'000 verticles at 60 fps (each circle is about 30 verticles, which is about 10'000 circles.
#include <SFML/Graphics.hpp>
#include <cmath>
#include <iostream>
#include <sstream>
#define WIDTH 800
#define HEIGHT 800
using namespace std;
template <typename T>
std::string to_string_with_precision(const T a_value, const int n = 6)
{
std::ostringstream out;
out.precision(n);
out << std::fixed << a_value;
return out.str();
}
void addCircle(sf::VertexArray &array, sf::Vector2f position, float radius, sf::Color color) {
size_t count = 30;
for (int i = 0; i < count; i += 1) {
sf::Vertex v0;
v0.position = sf::Vector2f(position.x, position.y);
v0.color = color;
array.append(v0);
sf::Vertex v1;
float angle = i * 2 * M_PI / count;
v1.position = sf::Vector2f(position.x + cos(angle) * radius, position.y + sin(angle) * radius);
v1.color = color;
array.append(v1);
sf::Vertex v2;
angle = (i + 1) * 2 * M_PI / count;
v2.position = sf::Vector2f(position.x + cos(angle) * radius, position.y + sin(angle) * radius);
v2.color = color;
array.append(v2);
}
}
#define FRAMERATE 120
int main() {
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), "RTREE", sf::Style::Close);
// Fps text
sf::Font font;
if (!font.loadFromFile("../assets/collegiate.ttf")) {
std::cout << "Error loading font" << std::endl;
}
sf::Text fps;
fps.setFont(font);
fps.setPosition(10, 10);
fps.setCharacterSize(16);
fps.setFillColor(sf::Color::White);
// Time management
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
sf::Time timePerFrame = sf::seconds(1.f / FRAMERATE);
sf::Time timeSinceLastDraw = sf::Time::Zero;
window.setFramerateLimit(FRAMERATE);
float vr = 0;
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) window.close();
}
size_t count = 15;
sf::Color color = sf::Color::Red;
color.a = 50;
sf::Color color2 = sf::Color::Blue;
color2.a = 20;
sf::VertexArray objects(sf::Triangles);
for (int k = 0; k < 5; k++) {
sf::Color c = k % 2 ? color : color2;
for (int j = 20; j < 400; j += 5) {
for (int i = 0; i < count; i++) {
float angle = i * 2 * M_PI / count;
angle += (i % 2 ? vr : -vr) * k * (k % 2 ? 1 : -1);
addCircle(objects, sf::Vector2f(WIDTH / 2 + cos(angle) * j, HEIGHT / 2 + sin(angle) * j), j / 5, c);
}
}
}
timeSinceLastDraw = clock.restart();
timeSinceLastUpdate += timeSinceLastDraw;
double timeFps = 1.f / timeSinceLastDraw.asSeconds();
fps.setString("verticles: " + to_string_with_precision(objects.getVertexCount(), 0) + " fps: " + to_string_with_precision(timeFps, 0));
while (timeSinceLastUpdate > timePerFrame) {
timeSinceLastUpdate -= timePerFrame;
vr += 0.01;
}
window.clear();
window.draw(objects);
window.draw(fps);
window.display();
}
}

C++ Sandbox Game Low Performance Difficulty

I started Learning C++ yesterday And In that time i was rewriting my java "Falling Sand" Sandbox Game code in C++ using SFML (bit simplified since i don't know C++). but Performance in C++ was much worse in than java, what could be the reason for it, I Know this is very unfocused question, but my code is simple, i probably have a newbie mistakes which should be easy to correct.
#include <SFML/Graphics.hpp>
#include <iostream>
sf::Clock sclock;
const int WIDTH = 1440, HEIGHT = 960;
const char Blank = 0, Sand = 1, Water = 2;
const char* title = "Sandbox Simulation";
char map[WIDTH*HEIGHT];
sf::Vector2i mousePos;
int dist(int x1, int x2, int y1, int y2) {
return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
int localBrushSize = 48;
short halfBrush = (short)floor(localBrushSize / 2);
char chosen = Sand;
void place() {
int randY = 0;
int randX = 0;
randX = randY = 1;
for (int y = mousePos.y - halfBrush; y <= mousePos.y + halfBrush; y += randY) {
for (int x = mousePos.x - halfBrush; x <= mousePos.x + halfBrush; x += randX) {
int I = x + y * WIDTH;
int distance = dist(mousePos.x, x, mousePos.y, y);
if (distance < halfBrush && I > 0) {
map[I] = chosen;
}
}
}
}
float Delta_Time() {
return sclock.restart().asSeconds();
}
int main() {
map[11111] = 2;
sf::RenderWindow window(sf::VideoMode(WIDTH, HEIGHT), title);
sf::Event evnt;
sf::RectangleShape pixel(sf::Vector2f(1.0f, 1.0f));
window.clear();
while (window.isOpen()) {
while (window.pollEvent(evnt)) {
switch (evnt.type) {
case sf::Event::Closed:
window.close();
break;
}
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
mousePos = sf::Mouse::getPosition(window);
place();
}
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int I = x + y * WIDTH;
switch (map[I]) {
case Sand:
pixel.setPosition(x, y);
pixel.setFillColor(sf::Color::Yellow);
window.draw(pixel);
break;
case Water:
pixel.setPosition(x, y);
pixel.setFillColor(sf::Color::Cyan);
window.draw(pixel);
break;
}
}
}
window.display();
}
return 0;
}
You might be able to make a cached / "framebuffer" like this
TOTALLY untested concept code. WIDTH/HEIGHT might be mixed up, endianess is not OK, etc.
sf::Image image;
sf:Image.create(WIDTH, HEIGHT, sf::Color(0, 0, 0));
sf::Sprite sprite;
std::array<sf::Uint8, WIDTH * HEIGHT * 4> pixels; // you can reuse this. The 4 is the size of RGBA
...
for(int y = 0; y < HEIGHT; y++) {
for(int x = 0; x < WIDTH; x++) {
int offset = (x + y * WIDTH) * 4;
pixels[offset] = sf::Color::Yellow.toInteger(); // in case BIG/Litte endian confusion you might have to do the below.
//pixels[offset + 0 ] = 255; // R?
//pixels[offset + 1 ] = 255; // G?
//pixels[offset + 2 ] = 255; // B?
//pixels[offset + 3 ] = 255; // A?
}
}
image.LoadFromPixels(WIDTH, HEIGHT, pixels);
sprite.SetImage(image);
window.Draw(sprite);
window.Display();

Why does my program crash and give a "Segmentation fault (core dumped)" but only if I have too many objects?

I'm making a firework program thing in SFML. It looks nice and works until I make too many fireworks (particles). When the fireworks explode and create the particles the program crashes and gives a "Segmentation fault (core dumped)" error. The program doesn't slow down at all before the crash. When it happens there is always 1025 particles. Fireworks are also particles. I don't think it helps but i'm on linux.
My code:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cmath>
sf::RenderWindow window;
class Particle;
std::vector<Particle> particles;
float gravity = 0.5;
class Particle
{
public:
sf::Vector2f pos = sf::Vector2f(0, 0);
sf::Vector2f vel = sf::Vector2f(0, 0);
sf::Vector2f acc = sf::Vector2f(0, 0);
sf::CircleShape renderer = sf::CircleShape(2.5);
bool isRocket = false;
bool hasExploded = false;
int lifetime = 255;
Particle(sf::Vector2f position)
{
pos = position;
}
void ApplyForce(sf::Vector2f force)
{
acc += force;
}
void Update(int i)
{
if(!particles[i].isRocket)
{
vel.x *= 0.9;
vel.y *= 0.9;
lifetime -= 8;
renderer.setRadius(renderer.getRadius() - 0.2);
renderer.setFillColor(sf::Color(renderer.getFillColor().r, renderer.getFillColor().g, renderer.getFillColor().b, lifetime));
}
//Gravity
ApplyForce(sf::Vector2f(0, gravity));
vel += acc;
pos += vel;
acc.x = 0;
acc.y = 0;
if (particles[i].isRocket && !particles[i].hasExploded && particles[i].vel.y > 0)
{
particles[i].Explode(i);
}
if(lifetime < 0)
{
particles.erase(particles.begin() + i);
}
}
void Render()
{
renderer.setPosition(pos);
window.draw(renderer);
}
void Explode(int i)
{
particles[i].hasExploded = true;
sf::Color color = sf::Color(rand() % 255, rand() % 255, rand() % 255);
int explosionSize = rand() % 3 + 1;
for (int i = 0; i < explosionSize * 100; i++)
{
Particle fire(pos);
fire.renderer.setFillColor(sf::Color(color.r + (rand() % 32 - 16), color.g + (rand() % 32 - 16), color.b + (rand() % 32 - 16)));
fire.renderer.setRadius(rand() % 5 + 2);
particles.push_back(fire);
//color.r + (rand() % 32 - 16), color.g + (rand() % 32 - 16), color.b + (rand() % 32 - 16)
float angle = (float(rand())/float((RAND_MAX)) * 2 * M_PI);
float velocity = (float(rand())/float((RAND_MAX)) * 8 * explosionSize);
particles[particles.size() - 1].ApplyForce(sf::Vector2f(velocity * cos(angle), velocity * sin(angle)));
}
particles.erase(particles.begin() + i);
}
};
void sendRocket()
{
Particle firework(sf::Vector2f(rand() % window.getSize().x, window.getSize().y));
firework.isRocket = true;
particles.push_back(firework);
particles[particles.size() - 1].ApplyForce(sf::Vector2f(0, -((window.getSize().y * 0.025) + rand() % 8 - 4) ));
}
int main()
{
window.create(sf::VideoMode::getDesktopMode(), "Fireworks", sf::Style::Fullscreen);
window.setFramerateLimit(60);
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
}
}
if(rand() % 10 == 0)
{
sendRocket();
}
std::cout<<particles.size()<<std::endl;
for (int i = 0; i < particles.size(); i++)
{
particles[i].Update(i);
}
window.clear(sf::Color::Black);
for (int i = 0; i < particles.size(); i++)
{
particles[i].Render();
}
window.display();
}
return 0;
}
I'm not super good at programming so any other tips would be appreciated too.

Performant Threaded C++ Pixel Rendering: Fastest Way?

My goal is simple: I want to create a rendering system in C++ that can draw thousands of bitmaps on screen. I have been trying to use threads to speed up the process but to no avail. In most cases, I have actually slowed down performance by using multiple threads. I am using this project as an educational exercise by not using hardware acceleration. That said, my question is this:
What is the best way to use several threads to accept a massive list of images to be drawn onto the screen and render them at break-neck speeds? I know that I won’t be able to create a system that can rival hardware accelerated graphics, but I believe that my idea is still feasible because the operation is so simple: copying pixels from one memory location to another.
My renderer design uses three core blitting operations: position, rotation, and scale of a bitmap image. I have it set up to only rotate an image when needed, and only scale an image when needed.
I have gone through several designs for this system. All of them too slow to get the job done (300 64x64 bitmaps at barely 60fps).
Here are the designs I have tried:
Immediately drawing a source bitmap on a destination bitmap for every image on screen (moderate speed).
Creating workers that accept a draw instruction and immediately begin working on it while other workers receive their instructions also (slowest).
Workers that receive packages of several instructions at a time (slower).
Saving all drawing instructions up and then parting them up in one swoop to several workers while other tasks (in theory) are being done (slowest).
Here is the bitmap class I am using to blit bitmaps onto each other:
class Bitmap
{
public:
Bitmap(int w, int h)
{
width = w;
height = h;
size = w * h;
pixels = new unsigned int[size];
}
virtual ~Bitmap()
{
if (pixels != 0)
{
delete[] pixels;
pixels = 0;
}
}
void blit(Bitmap *bmp, float x, float y, float rot, float sclx,
float scly)
{
// Position only
if (rot == 0 && sclx == 1 && scly == 1)
{
blitPos(bmp, x, y);
return;
}
// Rotate only
else if (rot != 0 && sclx == 1 && scly == 1)
{
blitRot(bmp, x, y, rot);
return;
}
// Scale only
else if (rot == 0 && (sclx != 1 || scly != 1))
{
blitScl(bmp, x, y, sclx, scly);
return;
}
/////////////////////////////////////////////////////////////////////////////
// If it is not one of those, you have to do all three... :D
/////////////////////////////////////////////////////////////////////////////
// Create a bitmap that is scaled to the new size.
Bitmap tmp((int)(bmp->width * sclx), (int)(bmp->height * scly));
// Find how much each pixel steps:
float step_x = (float)bmp->width / (float)tmp.width;
float step_y = (float)bmp->height / (float)tmp.height;
// Fill the scaled image with pixels!
float inx = 0;
int xOut = 0;
while (xOut < tmp.width)
{
float iny = 0;
int yOut = 0;
while (yOut < tmp.height)
{
unsigned int sample = bmp->pixels[
(int)(std::floor(inx) + std::floor(iny) * bmp->width)
];
tmp.drawPixel(xOut, yOut, sample);
iny += step_y;
yOut++;
}
inx += step_x;
xOut++;
}
blitRot(&tmp, x, y, rot);
}
void drawPixel(int x, int y, unsigned int color)
{
if (x > width || y > height || x < 0 || y < 0)
return;
if (color == 0x00000000)
return;
int index = x + y * width;
if (index >= 0 && index <= size)
pixels[index] = color;
}
unsigned int getPixel(int x, int y)
{
return pixels[x + y * width];
}
void clear(unsigned int color)
{
std::fill(&pixels[0], &pixels[size], color);
}
private:
void blitPos(Bitmap *bmp, float x, float y)
{
// Don't draw if coordinates are already past edges
if (x > width || y > height || y + bmp->height < 0 || x + bmp->width < 0)
return;
int from;
int to;
int destfrom;
int destto;
for (int i = 0; i < bmp->height; i++)
{
from = i * bmp->width;
to = from + bmp->width;
//////// Caps
// Bitmap is being drawn past the right edge
if (x + bmp->width > width)
{
int cap = bmp->width - ((x + bmp->width) - width);
to = from + cap;
}
// Bitmap is being drawn past the left edge
else if (x + bmp->width < bmp->width)
{
int cap = bmp->width + x;
from += (bmp->width - cap);
to = from + cap;
}
//////// Destination Maths
if (x < 0)
{
destfrom = (y + i) * width;
destto = destfrom + (bmp->width + x);
}
else
{
destfrom = x + (y + i) * width;
destto = destfrom + bmp->width;
}
// Bitmap is being drawn past either top or bottom edges
if (y + i > height - 1)
{
continue;
}
if (destfrom > size || destfrom < 0)
{
continue;
}
memcpy(&pixels[destfrom], &bmp->pixels[from], sizeof(unsigned int) * (to - from));
}
}
void blitRot(Bitmap *bmp, float x, float y, float rot)
{
float sine = std::sin(-rot);
float cosine = std::cos(-rot);
int x1 = (int)(-bmp->height * sine);
int y1 = (int)(bmp->height * cosine);
int x2 = (int)(bmp->width * cosine - bmp->height * sine);
int y2 = (int)(bmp->height * cosine + bmp->width * sine);
int x3 = (int)(bmp->width * cosine);
int y3 = (int)(bmp->width * sine);
int minx = (int)std::min(0, std::min(x1, std::min(x2, x3)));
int miny = (int)std::min(0, std::min(y1, std::min(y2, y3)));
int maxx = (int)std::max(0, std::max(x1, std::max(x2, x3)));
int maxy = (int)std::max(0, std::max(y1, std::max(y2, y3)));
int w = maxx - minx;
int h = maxy - miny;
int srcx;
int srcy;
int dest_x;
int dest_y;
unsigned int color;
for (int sy = miny; sy < maxy; sy++)
{
for (int sx = minx; sx < maxx; sx++)
{
srcx = sx * cosine + sy * sine;
srcy = sy * cosine - sx * sine;
dest_x = x + sx;
dest_y = y + sy;
if (dest_x <= width - 1 && dest_y <= height - 1
&& dest_x >= 0 && dest_y >= 0)
{
color = 0;
// Only grab a pixel if it is inside of the src image
if (srcx < bmp->width && srcy < bmp->height && srcx >= 0 &&
srcy >= 0)
color = bmp->getPixel(srcx, srcy);
// Only this pixel if it is not completely transparent:
if (color & 0xFF000000)
// Only if the pixel is somewhere between 0 and the bmp size
if (0 < srcx < bmp->width && 0 < srcy < bmp->height)
drawPixel(x + sx, y + sy, color);
}
}
}
}
void blitScl(Bitmap *bmp, float x, float y, float sclx, float scly)
{
// Create a bitmap that is scaled to the new size.
int finalwidth = (int)(bmp->width * sclx);
int finalheight = (int)(bmp->height * scly);
// Find how much each pixel steps:
float step_x = (float)bmp->width / (float)finalwidth;
float step_y = (float)bmp->height / (float)finalheight;
// Fill the scaled image with pixels!
float inx = 0;
int xOut = 0;
float iny;
int yOut;
while (xOut < finalwidth)
{
iny = 0;
yOut = 0;
while (yOut < finalheight)
{
unsigned int sample = bmp->pixels[
(int)(std::floor(inx) + std::floor(iny) * bmp->width)
];
drawPixel(xOut + x, yOut + y, sample);
iny += step_y;
yOut++;
}
inx += step_x;
xOut++;
}
}
public:
int width;
int height;
int size;
unsigned int *pixels;
};
Here is some code showing the latest method I have tried: saving up all instructions and then giving them to workers once they have all been received:
class Instruction
{
public:
Instruction() {}
Instruction(Bitmap* out, Bitmap* in, float x, float y, float rot,
float sclx, float scly)
: outbuffer(out), inbmp(in), x(x), y(y), rot(rot),
sclx(sclx), scly(scly)
{ }
~Instruction()
{
outbuffer = nullptr;
inbmp = nullptr;
}
public:
Bitmap* outbuffer;
Bitmap* inbmp;
float x, y, rot, sclx, scly;
};
Layer Class:
class Layer
{
public:
bool empty()
{
return instructions.size() > 0;
}
public:
std::vector<Instruction> instructions;
int pixel_count;
};
Worker Thread Class:
class Worker
{
public:
void start()
{
done = false;
work_thread = std::thread(&Worker::processData, this);
}
void processData()
{
while (true)
{
controller.lock();
if (done)
{
controller.unlock();
break;
}
if (!layers.empty())
{
for (int i = 0; i < layers.size(); i++)
{
for (int j = 0; j < layers[i].instructions.size(); j++)
{
Instruction* inst = &layers[i].instructions[j];
inst->outbuffer->blit(inst->inbmp, inst->x, inst->y, inst->rot, inst->sclx, inst->scly);
}
}
layers.clear();
}
controller.unlock();
}
}
void finish()
{
done = true;
}
public:
bool done;
std::thread work_thread;
std::mutex controller;
std::vector<Layer> layers;
};
Finally, the Render Manager Class:
class RenderManager
{
public:
RenderManager()
{
workers.reserve(std::thread::hardware_concurrency());
for (int i = 0; i < 1; i++)
{
workers.emplace_back();
workers.back().start();
}
}
void layer()
{
layers.push_back(current_layer);
current_layer = Layer();
}
void blit(Bitmap* out, Bitmap* in, float x, float y, float rot, float sclx, float scly)
{
current_layer.instructions.emplace_back(out, in, x, y, rot, sclx, scly);
}
void processInstructions()
{
if (layers.empty())
layer();
lockall();
int index = 0;
for (int i = 0; i < layers.size(); i++)
{
// Evenly distribute the layers in a round-robin fashion
Layer l = layers[i];
workers[index].layers.push_back(layers[i]);
index++;
if (index >= workers.size()) index = 0;
}
layers.clear();
unlockall();
}
void lockall()
{
for (int i = 0; i < workers.size(); i++)
{
workers[i].controller.lock();
}
}
void unlockall()
{
for (int i = 0; i < workers.size(); i++)
{
workers[i].controller.unlock();
}
}
void finish()
{
// Wait until every worker is done rendering
lockall();
// At this point, we know they have nothing more to draw
unlockall();
}
void endRendering()
{
for (int i = 0; i < workers.size(); i++)
{
// Send each one an exit code
workers[i].finish();
}
// Let the workers finish and then return
for (int i = 0; i < workers.size(); i++)
{
workers[i].work_thread.join();
}
}
private:
std::vector<Worker> workers;
std::vector<Layer> layers;
Layer current_layer;
};
Here is a screenshot of what the 3rd method I tried, and it's results:
Sending packages of draw instructions
What would really be helpful is that if someone could simply point me in the right direction in regards to what method I should try. I have tried these four methods and have failed, so I stand before those who have done greater things than I for help. The least intelligent person in the room is the one that does not ask questions because his pride does not permit it. Please keep in mind though, this is my first question ever on Stack Overflow.

I'm working on a c++ project and I'm having trouble passing the rect0 object by reference

#define NOMINMAX // prevent Windows API from conflicting with "min" and "max"
#include <stdio.h> // C-style output. printf(char*,...), putchar(int)
#include <windows.h> // SetConsoleCursorPosition(HANDLE,COORD)
#include <conio.h> // _getch()
/**
* moves the console cursor to the given x/y coordinate
* 0, 0 is the upper-left hand coordinate. Standard consoles are 80x24.
* #param x
* #param y
*/
void moveCursor(int x, int y)
{
COORD c = {x,y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
struct Vec2
{
short x, y;
Vec2() : x(0), y(0) { }
Vec2(int x, int y) : x(x), y(y) { }
void add(Vec2 v)
{
x += v.x;
y += v.y;
}
void operator+=(const Vec2 other_)
{
x += other_.x;
y += other_.y;
};
};
class Rect
{
Vec2 min, max;
public:
Rect(int minx, int miny, int maxx, int maxy)
:min(minx,miny),max(maxx,maxy)
{}
Rect(){}
void draw(const char letter) const
{
for(int row = min.y; row < max.y; row++)
{
for(int col = min.x; col < max.x; col++)
{
if(row >= 0 && col >= 0)
{
moveCursor(col, row);
putchar(letter);
}
}
}
}
bool isOverlapping(Rect const & r) const
{
return !( min.x >= r.max.x || max.x <= r.min.x
|| min.y >= r.max.y || max.y <= r.min.y);
}
void translate(Vec2 const & delta)
{
min += (delta);
max += (delta);
}
void setMin(Vec2 const & min)
{
this->min = min;
}
void setMax(Vec2 const & max)
{
this->max = max;
}
Vec2 getMin()
{
return min;
}
Vec2 getMax()
{
return max;
}
void setRandom(Rect &r)
{
int posX, posY, height, width;
posX = rand() % 51;
posY = rand() % 21;
height = 2 + rand() % 11;
width = 2 + rand() % 11;
height = height / 2;
width = width / 2;
min.x = posX - width;
min.y = posY - height;
max.x = posX + width;
max.y = posY + height;
}
};
int main()
{
// initialization
Rect * userRect = new Rect(7, 5, 10, 9);
Rect rect0(10, 2, 14, 4);
Rect rect1(1, 6, 5, 15);
Rect testSetRandom;
int userInput;
do
{
// draw
rect0.draw('0');
rect1.draw('1');
moveCursor(0, 0); // re-print instructions
printf("move with 'w', 'a', 's', and 'd'");
userRect->draw('#');
// user input
userInput = _getch();
// update
Vec2 move;
switch(userInput)
{
case 'w': move = Vec2( 0,-1); break;
case 'a': move = Vec2(-1, 0); break;
case 's': move = Vec2( 0,+1); break;
case 'd': move = Vec2(+1, 0); break;
}
userRect->draw(' '); // un-draw before moving
userRect->translate(move);
}while(userInput != 27); // escape key
delete userRect;
return 0;
}
// Here is what I am trying to do:
// 3) Random rectangles, by reference and by pointer
// a) create a method with the method signature "void setRandom(Rect & r)".
// This function will give the passed-in Rect object a random location.
// The random x should be between 0 and 50 x. The random y should be
// between 0 and 20. Limit the possible width and height to a minimum of 2
// and a maximum of 10.
// b) test "void setRandom(Rect & r)" on the local Rect object "rect0".
// c) create a method with the method signature
// "void setRandomByPointer(Rect * r)", which functions the same as
// "void setRandom(Rect & r)", except that the argument is
// passed-by-pointer.
// d) test "void setRandomByPointer(Rect * r)" on the local Rect object
// "rect1".
In the comments just above is an explanation of what I'm trying to do. I feel I have over complicated a very simple matter. I want to create a method that takes an object by reference and draws it in a random location. Then I want to do the same thing by pointer. The two signatures I'm starting with is "void setRandom(Rect & r)" and "void setRandomByPointer(Rect * r)". I will test each of them out using the object rect0(10, 2, 14, 4).
void setRandom(Rect& r)
{
int posX, posY, height, width;
posX = rand() % 51;
posY = rand() % 21;
height = 2 + rand() % 11;
width = 2 + rand() % 11;
height = height / 2;
width = width / 2;
r.min.x = posX - width;
r.min.y = posY - height;
r.max.x = posX + width;
r.max.y = posY + height;
}
And with pointer
void setRandom(Rect* r)
{
int posX, posY, height, width;
posX = rand() % 51;
posY = rand() % 21;
height = 2 + rand() % 11;
width = 2 + rand() % 11;
height = height / 2;
width = width / 2;
r->min.x = posX - width;
r->min.y = posY - height;
r->max.x = posX + width;
r->max.y = posY + height;
}
Also this methods don't interact with this object, so they can be declared as static or moved outside of the class.