#include<SFML/Window.hpp>
#include<SFML/Graphics.hpp>
#include<cstdint>
#include<iostream>
const int width = 500;
const int height = 500;
int main(){
sf::RenderWindow window(sf::VideoMode(width, height), "Window", sf::Style::Close);
window.setVerticalSyncEnabled(true);
sf::Event event;
uint8_t *pixels = new uint8_t[height *width *4];
for(int i = 0; i < height * width; i+= 4){
pixels[i] = 00; //r
pixels[i + 1] = 00;//g
pixels[i + 2] = 00;//b
pixels[i + 3] = 255;//a
}
sf::Texture texture;
texture.create(width, height);
sf::Sprite sprite;
while(window.isOpen()){
while(window.pollEvent(event)){
if(event.type == sf::Event::Closed){
window.close();
}
}
window.clear(sf::Color::White);
texture.update(pixels);
sprite.setTexture(texture);
window.draw(sprite);
window.display();
}
delete pixels;
return 0;
}
The output I am getting for following program is :
I don't understand why only some part of the window is actually drawn. Since the program is very small I would normnally guess that the problem is created by switching the height and width variable but that is not the case here since both are equal.
The SFML documentation says that if I don't explicitly put the size of texture in sprite.setTexture() it will default to the size of the texture.
Why is this weird behaviour ? Am I missing something ?
for(int i = 0; i < height * width; i+= 4)
Your pixel buffer is of size height * width * 4, but you are only looping while i < height * width. Change the condition in your for loop to i < height * width * 4. Actually, it would make your code much clearer if you declared another variable to store that value. i.e.
int pixel_buffer_size = width * height * 4;
uint8_t *pixels = new uint8_t[pixel_buffer_size];
for(int i = 0; i < pixel_buffer_size; i+= 4) {
etc...
Related
in SDL we're trying to find the average colour of the screen. To do so we're reading all the pixel colour values and putting them into an array (Performance is not of concern), for some reason however, GetPixel always returns a colour (0,0,0,0). Ive already established that the RenderReadPixels works correctly since saving a screenshot works just fine.
const Uint32 format = SDL_PIXELFORMAT_ARGB8888;
SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, format);
SDL_RenderReadPixels(renderer, NULL, format, surface->pixels, surface->pitch);
float* coverage = new float[width*height]; // * allocates memory
coverage[0] = 1;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
SDL_Color col;
col = GetPixel(surface, i, j);
coverage[i * height + j] = (1/3)(col.r + col.b + col.g); //Return coverage value at i, j
std::cout << coverage[i * height + j]; //Always returns 0
std::cout << "\n";
}
}
SDL_Color GetPixel(SDL_Surface* srf, int x, int y)
{
SDL_Color color;
SDL_GetRGBA(get_pixel32(srf, x, y), srf->format, &color.r, &color.g, &color.b, &color.a);
return color;
}
Uint32 get_pixel32(SDL_Surface* surface, int x, int y)
{
//Convert the pixels to 32 bit
Uint32* pixels = (Uint32*)surface->pixels;
//Get the requested pixel
return pixels[(y * surface->w) + x];
}
1/3 is always 0 because of the way number promotion works in C++.
Best be explicit about what you want:
coverage[i * height + j] = float(col.r + col.b + col.g) / 3.0;
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();
So I need to draw one sprite like 5 times, moving another sprite some pixels forward, so they don't stack. My for loop didn't work and now I have no idea how to do this. I also created a class Hero, because I need to draw it's sprite only 1 time. When I run the program, it displays only 1 tower on nothing.
int main() {
sf::RenderWindow screen(sf::VideoMode(700, 580), "SFML Demo");
sf::Event event;
int posX = 0, posY = 0;
Image TileSet;
TileSet.loadFromFile("Town.png");
Hero My_Hero("Orc.png");
Texture TowerTexture;
TowerTexture.loadFromImage(TileSet);
Sprite Tower;
Tower.setTexture(TowerTexture);
Tower.setPosition(0, 0);
Tower.setTextureRect(IntRect(383, 96, 145, 280));
while (screen.isOpen()) {
while (screen.pollEvent(event)) {
if (event.type == sf::Event::EventType::Closed)
screen.close();
}
screen.clear();
for (int i = 0; i < 4; ++i) {
screen.draw(Tower);
posX += 40;
Tower.setPosition(posX, posY);
}
My_Hero.MoveHero();
screen.draw(My_Hero.getSprite());
screen.display();
}
}
Your problem come from posX.
You should set back posX to zero every frame.
Something like:
posX = 0;
for (int i = 0; i < 4; ++i) {
screen.draw(Tower);
posX += 40;
Tower.setPosition(posX, posY);
}
I got the following problem:
I'm somewhat new to C++, looked up how to make multidimensional arrays without predefinition of size, I found something and tried it. I got a Process returned 139 (0x8B) as an answer. I looked up everything I found about it but It didn't help me at all.
My system: Linux Mint 64 Bit, Editor: Code::Blocks and Clion
Project: https://github.com/blueburningcoder/AntWorld.git
essential code:
#include <SFML/Graphics.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace sf;
/*
* Tile: the background is out of tiles
*
* setSize:
* #param x: X-location of the Tile later on
* #param y: Y-location of the Tile later on
* #param height2: the height of the tile
* #param width2: the width of the tile
* (the 2 is there since the scope resolution operator didn't work for some reason)
* setting the size, position and color of the rect
*
*
* drawTile:
* #param renderWindow: the window the rect is drawn in
* drawing the rect
*/
class Tile {
private:
int locX, locY, height, width;
//
RectangleShape rect;
public:
void setSize(int x, int y, int height2, int width2){
locX = x;
locY = y;
height = height2;
width = width2;
rect.setSize(Vector2f(height, width));
rect.setFillColor(Color::Blue);
rect.setPosition(Vector2f(locX, locY));
}
void drawTile(RenderWindow *renderWindow){
renderWindow->draw(rect);
}
};
/*
* Maze: including all the Tiles, used to manipulate only specific Tiles
* #param xSize: how many tiles are gonna be in x direction
* #param ySize: how many tiles are gonna be in y direction
*
* drawMaze:
* #param renderWindow: needed for the Tile.drawTile method to draw on
* drawing all Tiles in the MAP
*/
class Maze {
private:
int sizeX = -1, sizeY = -1;
vector<vector<Tile> > MAP;
public:
Maze(int xSize, int ySize){
sizeX = xSize;
sizeY = ySize;
for(int i = 0; i < xSize; i++){
for(int j = 0; j < ySize; j++){
Tile tile;
tile.setSize(i * 35, j * 35, 30, 30);
// tile might not have been initialized?
MAP[i][j] = tile;
}
}
}
void drawMaze(RenderWindow *renderWindow){
// TODO: draw Tiles!
for(int i = 0; i < sizeX; i++){
for(int j = 0; j < sizeY; j++){
MAP[i][j].drawTile(renderWindow);
}
}
}
};
int main()
{
// Create the main window
RenderWindow app(VideoMode(800, 600), "SFML window");
// Load a sprite to display
Texture texture;
cout << "there's no error yet..." << endl;
if (!texture.loadFromFile("cb.bmp")) {
cout << "failed to load!" << endl;
return EXIT_FAILURE;
}
Sprite sprite(texture);
cout << "creating the maze ..." << endl;
// Creating a 10 x 10 Maze
Maze maze(10, 10);
// Start the game loop
while (app.isOpen())
{
// Process events
sf::Event event;
while (app.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
app.close();
}
cout << "gonna draw it ..." << endl;
// Clear screen
app.clear();
// Draw the sprite
app.draw(sprite);
// drawing the Maze
maze.drawMaze(&app);
// Update the window
app.display();
}
return EXIT_SUCCESS;
}
correct answer below
You cannot insert into a std::vector just via indexing, you need to call the appropriate constructor which allocates a fixed amount of space.
std::vector<int> array(4);
// array[0 ... 3] are now accessible.
So your declaration should be like this :
MAP = std::vector<std::vector<Tile>>(xSize, std::vector<Tile>(ySize));
// now access MAP[i][j]
// It basically reads, MAP has xSize number of elements where each defaults to a std::vector<Tile>(ySize).
Here is an example.
I've created a program using SDL in which a rectangle continuously collides within the walls of the program, but the collision checking is not working properly.
Here is the code:`
int main(int argc, char *argv[]){
//variable Initialization]
width = height = 45;
srcX = srcY = 0;
destY = destX = 0;
vlc = 1;
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
SDL_WM_SetCaption("Bouncing Balls","./ball.jpg");
backg = IMG_Load("./back.png");
ball = IMG_Load("./ball.jpg");
while (checkBounce){
//Increase velocity
destX += vlc;
destY += vlc;
//Collision Checking
if (destX < 0){
destX = 0;
vlc = -vlc;
destX += vlc;
}
if (destY < 0){
destY = 0;
vlc = -vlc;
destY += vlc;
}
if (destY + height > 480){
destY = 480 - height;
vlc = -vlc;
}
if (destX + width > 640){
destX = 640 - width;
vlc = -vlc;
}
if (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT)
checkBounce = false;
}
//Applying Surfaces
applySurface(0, 0, backg, screen);
applyBall(srcX, srcY, destX, destY, width, height, ball, screen);
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}
Here is the gif Image What is happening :Bouncing Rectangle.gif
I'm assuming that the expected result is for the rectangle to bounce off of the walls correctly?
You need to separate your velocity in to x and y components rather than using a single number. This is because velocity is two dimensional.
Your program is causing both the x and y components to become negative whenever a collision is detected. This causes the rectangle to bounce backwards along its path.
Here's an edit:
int main(int argc, char *argv[]){
//variable Initialization]
width = height = 45;
srcX = srcY = 0;
destY = destX = 0;
vlcX = 1;
vlcY = 1;
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
SDL_WM_SetCaption("Bouncing Balls","./ball.jpg");
backg = IMG_Load("./back.png");
ball = IMG_Load("./ball.jpg");
while (checkBounce){
//Increase velocity
destX += vlcX;
destY += vlcY;
//Collision Checking
if (destX < 0){
destX = 0;
vlcX = -vlcX;
destX += vlcX;
}
if (destY < 0){
destY = 0;
vlcY = -vlcY;
destY += vlcY;
}
if (destY + height > 480){
destY = 480 - height;
vlcY = -vlcY;
}
if (destX + width > 640){
destX = 640 - width;
vlcX = -vlcX;
}
if (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT)
checkBounce = false;
}
//Applying Surfaces
applySurface(0, 0, backg, screen);
applyBall(srcX, srcY, destX, destY, width, height, ball, screen);
SDL_Flip(screen);
}
SDL_Quit();
return 0;
}