How to remove green pixels from character green screen - c++

I am a beginner with C++, so please forgive me, but I am trying to bring two images together. One of them is a character in a green screen and a real life location. I was able to successfully mix the two images together on Visual Studio, however, I'm trying to remove the green pixels from the character and replace them with the background image. How can I use the green pixels. Any form of help would be much appreciated. Here is my code:
#include <iostream>
#include <SFML/Graphics.hpp>
using namespace sf;
using namespace std;
int main()
{
Texture tex;
if (!tex.loadFromFile("yoda.png")) {
cout << "Couldn’t Load Yoda Image";
exit(1);
}
Texture tex2;
if (!tex2.loadFromFile("prague.png")) {
cout << "Couldn’t Load Prague Image";
exit(1);
}
Image yodaImage;
yodaImage = tex.copyToImage();
Image pragueImage;
pragueImage = tex2.copyToImage();
RenderWindow window(VideoMode(1024, 800), "Assignment 3");
Sprite sprite;
sprite.setTexture(tex);
Vector2u textureSize = tex.getSize();
sprite.setPosition((1024 - textureSize.x) / 2,
(800 - textureSize.y) / 2);
Vector2u sz = yodaImage.getSize();
for (int y = 0; y < sz.y; y++) {
for (int x = 0; x < sz.x; x++) {
Color pragueC = pragueImage.getPixel(x,y);
Color yodaC = yodaImage.getPixel(x,y);
Color mixedC(
pragueC.r / 2 + yodaC.r / 2,
pragueC.g / 2 + yodaC.g / 2,
pragueC.b / 2 + yodaC.b / 2 );
yodaImage.setPixel(0, 0, mixedC);
}
}
tex.loadFromImage(yodaImage);
window.clear();
window.draw(sprite);
window.display();
while (true);
}

Related

Try to build and get Open Image Denoise working with Bazel

The bounty expires in 7 days. Answers to this question are eligible for a +500 reputation bounty.
Vertexwahn wants to draw more attention to this question.
Currently, I try to get Open Image Denoise to work with Bazel.
Therefore, I implemented rules_oidn.
To try it out, you can do a
git clone https://github.com/Vertexwahn/rules_oidn.git
cd rules_oidn
cd tests
Run example with Ubuntu 22.04:
bazel run --config=gcc11 //:example
Run example with Visual Studio 2022:
bazel run --config=vs2022 //:example
The example takes a noisy image and denoises it.
...
int main() {
cout << "Simple denoising example" << endl;
Image3f color = load_image_openexr("data/cornel_box.naive_diffuse.box_filter.spp128.embree.exr");
//Image3f color = load_image_openexr("data/noisy_10spp.exr");
Image3f normal = load_image_openexr("data/normal_10spp.exr");
Image3f albedo = load_image_openexr("data/albedo_10spp.exr");
Image3f out{color.width(), color.height()};
// for debug reasons the color image can be initialized with a const color
if(false) {
for (int x = 0; x < color.width(); ++x) {
for (int y = 0; y < color.height(); ++y) {
color.set_pixel(x,y,.5f, .5f, .5f);
}
}
}
float* colorPtr = color.data();
float* albedoPtr = albedo.data();
float* normalPtr = normal.data();
float* outputPtr = out.data();
int width = out.width();
int height = out.height();
oidn::DeviceRef device = oidn::newDevice();
device.set("verbose", 1);
device.commit();
// Create a filter for denoising a beauty (color) image using optional auxiliary images too
oidn::FilterRef filter = device.newFilter("RT"); // generic ray tracing filter
filter.setImage("color", colorPtr, oidn::Format::Float3, width, height); // beauty
//filter.setImage("albedo", albedoPtr, oidn::Format::Float3, width, height); // auxiliary
//filter.setImage("normal", normalPtr, oidn::Format::Float3, width, height); // auxiliary
filter.setImage("output", outputPtr, oidn::Format::Float3, width, height); // denoised beauty
filter.set("hdr", true); // beauty image is HDR
filter.commit();
// Filter the image
filter.execute();
// Check for errors
const char* errorMessage;
if (device.getError(errorMessage) != oidn::Error::None) {
std::cout << "Error: " << errorMessage << std::endl;
}
store_open_exr("denoised.exr", out);
return 0;
}
Unfortunately, the denoised image contains black stripes:
I tested the same input with https://github.com/DeclanRussell/IntelOIDenoiser and got the expected result (without black stripes).
If I choose a constant color image, e.g.
// for debug reasons the color image can be initialized with a const color
if(true) {
for (int x = 0; x < color.width(); ++x) {
for (int y = 0; y < color.height(); ++y) {
color.set_pixel(x,y,.5f, .5f, .5f);
}
}
}
I also get black stripes.
Currently, I am missing a good strategy to find the issue.
Any hints or solutions to fix the issue are welcome.

Visual Studio 2017 Exception Unhandled

I'm a novice programmer trying to follow a tuturial on recreating a game on Steam called Timber(I believe). The program was working fine and I had almost completed the tutrial, but I ran into trouble when I added the code:
for (int i = 0 < NUM_BRANCHES; i++;)
{
branches[i].setTexture(textureBranch);
branches[i].setPosition(-2000, -2000);
// Set the sprite's origin to dead center
// We can then spin it around without changing its position
branches[i].setOrigin(220, 20);
}
Visual Studio says: branches[i].setPosition(-2000, -2000); Unhandled exception thrown: write access violation.
this was 0x59AF28. occurred
I'll also post the full code, apologies that it's a bit messy.
#include "stdafx.h"
#include <sstream>
#include <SFML\Graphics.hpp>
using namespace sf;
// Function declaration
void updateBranches(int seed);
const int NUM_BRANCHES = 6;
Sprite branches[NUM_BRANCHES];
// Where is the player/branch?
// Left or right
enum class side{ LEFT, RIGHT, NONE };
side branchPositions[NUM_BRANCHES];
int main()
{
// Creates a video mode object
VideoMode vm(1920, 1080);
// Creates and opens a window for the game
RenderWindow window(vm, "Timber!!!", Style::Fullscreen);
// Create a texture to hold a graphic on the GPU
Texture textureBackground;
// Load a graphic into the texture
textureBackground.loadFromFile("graphics/background.png");
// Create a sprite
Sprite spriteBackground;
// Attach the texture to the sprite
spriteBackground.setTexture(textureBackground);
// Set the spriteBackground to cover the screen
spriteBackground.setPosition(0, 0);
// Make a tree sprite
Texture textureTree;
textureTree.loadFromFile("graphics/tree.png");
Sprite spriteTree;
spriteTree.setTexture(textureTree);
spriteTree.setPosition(810, 0);
// Prepare the bee
Texture textureBee;
textureBee.loadFromFile("graphics/bee.png");
Sprite spriteBee;
spriteBee.setTexture(textureBee);
spriteBee.setPosition(0, 450);
// Is the be currently moving?
bool beeActive = false;
// How fast can the bee fly
float beeSpeed = 0.0f;
// Make 3 cloud sprites from 1 texture
Texture textureCloud;
// Load 1 new texture
textureCloud.loadFromFile("graphics/cloud.png");
// 3 new sprites with the same texture
Sprite spriteCloud1;
Sprite spriteCloud2;
Sprite spriteCloud3;
spriteCloud1.setTexture(textureCloud);
spriteCloud2.setTexture(textureCloud);
spriteCloud3.setTexture(textureCloud);
// Position the clouds off screen
spriteCloud1.setPosition(0, 0);
spriteCloud2.setPosition(0, -150);
spriteCloud3.setPosition(0, -300);
// Are the clouds currently on the screen?
bool cloud1Active = false;
bool cloud2Active = false;
bool cloud3Active = false;
// How fast is each cloud?
float cloud1Speed = 0.1f;
float cloud2Speed = 0.2f;
float cloud3Speed = 0.3f;
// Variables to control time itself
Clock clock;
// Time bar
RectangleShape timeBar;
float timeBarStartWidth = 400;
float timeBarHeight = 80;
timeBar.setSize(Vector2f(timeBarStartWidth, timeBarHeight));
timeBar.setFillColor(Color::Red);
timeBar.setPosition((1920 / 2) - timeBarStartWidth / 2, 980);
Time gameTimeTotal;
float timeRemaining = 6.0f;
float timeBarWidthPerSecond = timeBarStartWidth / timeRemaining;
// Track whether the game is running
bool paused = true;
// Draw some text
int score = 0;
sf::Text messageText;
sf::Text scoreText;
// Font
Font font;
font.loadFromFile("fonts/KOMIKAP_.ttf");
// Set the font of our message
messageText.setFont(font);
scoreText.setFont(font);
// Assign the actual message
messageText.setString("Press Enter to Start!");
scoreText.setString("score = 0");
// Make text really big
messageText.setCharacterSize(75);
scoreText.setCharacterSize(100);
// Choose a color
messageText.setFillColor(Color::White);
scoreText.setFillColor(Color::Black);
// Position the text
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
scoreText.setPosition(20, 20);
// Prepare 6 branches
Texture textureBranch;
textureBranch.loadFromFile("graphics/branch.png");
// Set the texture for each branch sprite
for (int i = 0 < NUM_BRANCHES; i++;)
{
branches[i].setTexture(textureBranch);
branches[i].setPosition(-2000, -2000);
// Set the sprite's origin to dead center
// We can then spin it around without changing its position
branches[i].setOrigin(220, 20);
}
while (window.isOpen())
{
/*
**************
Handles the player input
**************
*/
if (Keyboard::isKeyPressed(Keyboard::Escape))
{
window.close();
}
// Start the game
if (Keyboard::isKeyPressed(Keyboard::Return))
{
paused = false;
// Reset the time and the score
score = 0;
timeRemaining = 5;
}
/*
**************
Update the scene
**************
*/
if (!paused)
{
// Measure time
Time dt = clock.restart();
// Subtract from the amount of time remaining
timeRemaining -= dt.asSeconds();
// size up the time bar
timeBar.setSize(Vector2f(timeBarWidthPerSecond *
timeRemaining, timeBarHeight));
if (timeRemaining <= 0.0f)
{
// Pause the game
paused = true;
// Change the message shown to the player
messageText.setString("Out of time");
// Reposition the text base on its new size
FloatRect textRect = messageText.getLocalBounds();
messageText.setOrigin(textRect.left +
textRect.width / 2.0f,
textRect.top +
textRect.height / 2.0f);
messageText.setPosition(1920 / 2.0f, 1080 / 2.0f);
}
// Setup the bee
if (!beeActive)
{
// How fast is the bee
srand((int)time(0) * 10);
beeSpeed = (rand() % 400) + 350;
// How high is the bee
srand((int)time(0) * 10);
float height = (rand() % 650) + 850;
spriteBee.setPosition(1921, height);
beeActive = true;
}
else
// Move the bee
{
spriteBee.setPosition(
spriteBee.getPosition().x -
(beeSpeed * dt.asSeconds()),
spriteBee.getPosition().y);
// Has the bee reached the right hand edge of the screen?
if (spriteBee.getPosition().x < -100)
{
// Set it up ready to be a whole new bee next frame
beeActive = false;
}
}
// Manage the clouds
// Cloud 1
if (!cloud1Active)
{
// How fast is the cloud
srand((int)time(0) * 10);
cloud1Speed = (rand() % 150);
// How high is the cloud
srand((int)time(0) * 10);
float height = (rand() % 200);
spriteCloud1.setPosition(-300, height);
cloud1Active = true;
}
else
{
spriteCloud1.setPosition(
spriteCloud1.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud1.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud1.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud1Active = false;
}
}
// Cloud 2
if (!cloud2Active)
{
// How fast is the cloud
srand((int)time(0) * 20);
cloud2Speed = (rand() % 200);
// How high is the cloud
srand((int)time(0) * 20);
float height = (rand() % 300);
spriteCloud2.setPosition(-200, height);
cloud2Active = true;
}
else
{
spriteCloud2.setPosition(
spriteCloud2.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud2.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud2.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud2Active = false;
}
}
// Cloud 3
if (!cloud3Active)
{
// How fast is the cloud
srand((int)time(0) * 30);
cloud3Speed = (rand() % 250);
// How high is the cloud
srand((int)time(0) * 30);
float height = (rand() % 150);
spriteCloud3.setPosition(-100, height);
cloud3Active = true;
}
else
{
spriteCloud3.setPosition(
spriteCloud3.getPosition().x +
(cloud1Speed * dt.asSeconds()),
spriteCloud3.getPosition().y);
// Has the cloud reached the right hand edge of the screen?
if (spriteCloud3.getPosition().x > 1920)
{
// Set it up ready to be a whole new cloud next frame
cloud3Active = false;
}
}
// Update the score text
std::stringstream ss;
ss << "Score = " << score;
scoreText.setString(ss.str());
// Update the branch sprites
for (int i = 0; i < NUM_BRANCHES; i++)
{
float height = i * 150;
if (branchPositions[i] == side::LEFT)
{
// Move the sprite to the left side
branches[i].setPosition(610, height);
// Flip the sprite around the other way
branches[i].setRotation(180);
}
else if (branchPositions[i] == side::RIGHT)
{
// Move the sprite to the right side
branches[i].setPosition(1330, height);
// Set the sprite rotation to normal
branches[i].setRotation(0);
}
else
{
// Hide the branch
branches[i].setPosition(3000, height);
}
}
} // End if(!paused)
/*
**************
Draw the scene
**************
*/
// Clear everything from the last frame
window.clear();
// Draw our game scene here
window.draw(spriteBackground);
// Draw the clouds
window.draw(spriteCloud1);
window.draw(spriteCloud2);
window.draw(spriteCloud3);
// Draw the branches
for (int i = 0; i < NUM_BRANCHES; i++)
{
window.draw(branches[i]);
}
// Draw the tree
window.draw(spriteTree);
// Draw the insect
window.draw(spriteBee);
// Draw the score
window.draw(scoreText);
//Draw the timebar
window.draw(timeBar);
if (paused)
{
// Draw our message
window.draw(messageText);
}
// Show everyting we just drew
window.display();
}
return 0;
}
// Function definition
void updateBranches(int seed)
{
// Move all the branches down on place
for (int j = NUM_BRANCHES - 1; j > 0; j--)
{
branchPositions[j] = branchPositions[j - 1];
}
// Spawn a new branch at postion 0
// LEFt, RIGHT, NONE
srand((int)time(0) + seed);
int r = (rand() % 5);
switch (r)
{
case 0:
branchPositions[0] = side::LEFT;
break;
case 1:
branchPositions[0] = side::RIGHT;
break;
default:
branchPositions[0] = side::NONE;
break;
}
}
setPosition() requires an sf::Vector2f. So you could fix your code by changing that line to:
branches[i].setPosition(sf::Vector2f(-2000, -2000))

Low framerate with only map and minimap drawing (SFML)

I'm working on a small "game" like project as a practice, and I've managed to get my framerate down to not even 3 FPS. While the only thing that is being drawn is screen filling tiles and a minimap.
Now I've found that the problem is with the minimap, without it caps at 60 FPS. But unfortunately I'm not experienced enough to find out what the real problem is with it...
My draw function:
void StateIngame::draw()
{
m_gui.removeAllWidgets();
m_window.setView(m_view);
// Frame counter
float ct = m_clock.restart().asSeconds();
float fps = 1.f / ct;
m_time = ct;
char c[10];
sprintf(c, "%f", fps);
std::string fpsStr(c);
sf::String str(fpsStr);
auto fpsText = tgui::Label::create();
fpsText->setText(str);
fpsText->setTextSize(16);
fpsText->setPosition(15, 15);
m_gui.add(fpsText);
//////////////
// Draw map //
//////////////
int camOffsetX, camOffsetY;
int tileSize = m_map.getTileSize();
Tile tile;
sf::IntRect bounds = m_camera.getTileBounds(tileSize);
camOffsetX = m_camera.getTileOffset(tileSize).x;
camOffsetY = m_camera.getTileOffset(tileSize).y;
// Loop and draw each tile
// x and y = counters, tileX and tileY is the coordinates of the tile being drawn
for (int y = 0, tileY = bounds.top; y < bounds.height; y++, tileY++)
{
for (int x = 0, tileX = bounds.left; x < bounds.width; x++, tileX++)
{
try {
// Normal view
m_window.setView(m_view);
tile = m_map.getTile(tileX, tileY);
tile.render((x * tileSize) - camOffsetX, (y * tileSize) - camOffsetY, &m_window);
} catch (const std::out_of_range& oor)
{}
}
}
bounds = sf::IntRect(bounds.left - (bounds.width * 2), bounds.top - (bounds.height * 2), bounds.width * 4, bounds.height * 4);
for (int y = 0, tileY = bounds.top; y < bounds.height; y++, tileY++)
{
for (int x = 0, tileX = bounds.left; x < bounds.width; x++, tileX++)
{
try {
// Mini map
m_window.setView(m_minimap);
tile = m_map.getTile(tileX, tileY);
sf::RectangleShape miniTile(sf::Vector2f(4, 4));
miniTile.setFillColor(tile.m_color);
miniTile.setPosition((x * (tileSize / 4)), (y * (tileSize / 4)));
m_window.draw(miniTile);
} catch (const std::out_of_range& oor)
{}
}
}
// Gui
m_window.setView(m_view);
m_gui.draw();
}
The Tile class has a variable of type sf::Color which is set during map generating. This color is then used to draw the minimap instead of the 16x16 texture that is used for the map itself.
So when I leave out the minimap drawing, and only draw the map itself, it's more fluid than I could wish for...
Any help is appreciated!
You are generating the view completly new for every frame. Do this once on startup should be enought.

2D Diamond (isometric) map editor - Textures extended infinitely?

I'm currently developing a 2D isometric map editor.
I display entity(cube, player) which contains points and textures.
Each cubes are composed by 12 points.(12 points, but handled as 3 sides of 4 points when displayed by sfml(sf::VertexArray).
(I know I include some '.cpp' times to times, I have a problem with my IDE(visual studio) which I'm trying to resolve, please do not care about it.)
main.cpp
#pragma once
#include "globalfunctions.h" //global functions + main headers + class headers
int main() {
int mapSize = 0;
int cubeSize = 0;
cout << "Map size: "; cin >> mapSize; cout << endl;
cout << "Cube size: "; cin >> cubeSize; cout << endl;
int windowWidth = (mapSize * cubeSize) - (cubeSize * 2);
int windowHeight = ((mapSize * cubeSize) - (cubeSize * 2)) / 2;
renderWindow window(windowWidth, windowHeight, mapSize, cubeSize);
int nbMaxTextures = 9;
for (int t = 0; t < nbMaxTextures; t++) {
window.loadTexture("test", t);
}
window.run();
return EXIT_SUCCESS;
}
globalfunctions.h
#pragma once
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <iostream>
#include <math.h>
//#include <sstream>
#include <vector>
using namespace std;
sf::Vector2u isometricToCartesian(int i, int j, int cubeSize) {
sf::Vector2u carth;
carth.x = (j - i) * (cubeSize / 2);
carth.y = (j + i) * (cubeSize / 4);
return carth;
}
sf::Vector2u cartesianToIsometric(int x, int y, int cubeSize) {//TODO
sf::Vector2u iso;
iso.x = 0;
iso.y = 0;
return iso;
}
#include "entity.h"
#include "renderWindow.h"
renderWindow.h
#pragma once
class renderWindow {
public:
renderWindow(float WIDTH, float HEIGHT, int MAPSIZE, int CUBESIZE);
void run();
void loadTexture(sf::String folder, int numTexture);
//SETTERS
//...
//GETTERS
//...
private:
int mCurrentLayerID;
int mMapSize;
int mCubeSize;
int mSelectedTexture;
vector<entity> mMap;
sf::RenderWindow mWindow;
vector<sf::Texture> mTextures;
sf::Texture mMemoryTexture;
void processEvent();
void update(sf::Time deltaTime);
void render();
//CUBE ACTION-------------------------------------------
void addCube(int layerID, float x, float y);
entity& getCube(int ID);
entity& getCubeAt(float x, float y);
vector<sf::VertexArray> loadCube(int cubeID);//UPDATE DATA LIKE COORDINATES -> create/chnge the vertex
void drawCube(int cubeID);//draw the vertex
//VARIABLES
vector<sf::VertexArray> verticesSide1;
vector<sf::VertexArray> verticesSide2;
vector<sf::VertexArray> verticesSide3;
//CUBE ACTION-------------------------------------------
};
#include "renderWindow.cpp"
renderWindow.cpp
#pragma once
renderWindow::renderWindow(float WIDTH, float HEIGHT, int MAPSIZE, int CUBESIZE) : mWindow(sf::VideoMode(WIDTH, HEIGHT), "") {
mMapSize = MAPSIZE;
mCubeSize = CUBESIZE;
mSelectedTexture = 6;
mCurrentLayerID = -1;
int x = 0;
int y = 0;
//default layer
for (int j = 0; j < mMapSize; j++) {
for (int i = 0; i < mMapSize; i++) {
x = isometricToCartesian(i, j, mCubeSize).x;
y = isometricToCartesian(i, j, mCubeSize).y;
addCube(0, x, y);
}
}
for (int c = 0; c < mMap.size(); c++) {
verticesSide1.push_back(loadCube(c)[0]);
verticesSide2.push_back(loadCube(c)[1]);
verticesSide3.push_back(loadCube(c)[2]);
//then only do that when something the cube's coordinate changed
}
}
void renderWindow::run() {
sf::Clock clock;
sf::Time timeSinceLastUpdate = sf::Time::Zero;
sf::Time TimePerFrame = sf::seconds(1.f / 60.f);
while (mWindow.isOpen()) {
processEvent();
timeSinceLastUpdate += clock.restart();
while (timeSinceLastUpdate > TimePerFrame) {
timeSinceLastUpdate -= TimePerFrame;
processEvent();
update(TimePerFrame);
}
render();
}
}
void renderWindow::loadTexture(sf::String folder, int numTexture) {
if (mMemoryTexture.loadFromFile("textures/" + folder + "/" + to_string(numTexture) + ".jpg"))
mTextures.push_back(mMemoryTexture);
else
cout << "Texture n°" << numTexture << " as failed to load." << endl;
}
//SETTERS
//...
//GETTERS
//...
//PRIVATE METHODE
void renderWindow::processEvent() {
sf::Event event;
while (mWindow.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
mWindow.close();
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Escape)
mWindow.close();
break;
case sf::Event::MouseButtonPressed:
if (event.MouseButtonPressed == sf::Mouse::Left)
getCubeAt(event.mouseButton.x, event.mouseButton.y).setTexture(0, mSelectedTexture);//TEST
getCubeAt(event.mouseButton.x, event.mouseButton.y).setTexture(1, mSelectedTexture + 1);//TEST
getCubeAt(event.mouseButton.x, event.mouseButton.y).setTexture(2, mSelectedTexture + 2);//TEST
break;
/*case sf::Event::MouseMoved:
cout << "(" << event.mouseMove.x << ", " << event.mouseMove.y << ")" << endl;
break;*/
}
}
}
void renderWindow::update(sf::Time deltaTime) {
//REMEMBER: distance = speed * time
//MOVEMENT, ANIMATIONS ETC. ...
}
void renderWindow::render() {
mWindow.clear();
for (int c = 0; c < mMap.size(); c++) {
drawCube(c);
}
mWindow.display();
}
//CUBE ACTION-------------------------------------------
void renderWindow::addCube(int layerID, float x, float y) {
//Thoses make the code more readable:
int half_cubeSize = mCubeSize / 2;
int oneQuarter_cubeSize = mCubeSize / 4;
int twoQuarter_cubeSize = oneQuarter_cubeSize * 2;
int treeQuarter_cubeSize = oneQuarter_cubeSize * 3;
mCurrentLayerID = layerID;
entity dummy(mMap.size(), 0, layerID);
dummy.addPoint(12);
dummy.addTexture(6);
dummy.addTexture(7);
dummy.addTexture(8);
//SIDE 1------------------------------------------------
dummy.setPoint(0, x, y + oneQuarter_cubeSize);
dummy.setPoint(1, x + half_cubeSize, y + twoQuarter_cubeSize);
dummy.setPoint(2, x + half_cubeSize, y + mCubeSize);
dummy.setPoint(3, x, y + treeQuarter_cubeSize);
//SIDE 2------------------------------------------------
dummy.setPoint(4, x + half_cubeSize, y + twoQuarter_cubeSize);
dummy.setPoint(5, x + mCubeSize, y + oneQuarter_cubeSize);
dummy.setPoint(6, x + mCubeSize, y + treeQuarter_cubeSize);
dummy.setPoint(7, x + half_cubeSize, y + mCubeSize);
//SIDE 3------------------------------------------------
dummy.setPoint(8, x, y + oneQuarter_cubeSize);
dummy.setPoint(9, x + half_cubeSize, y);
dummy.setPoint(10, x + mCubeSize, y + oneQuarter_cubeSize);
dummy.setPoint(11, x + half_cubeSize, y + twoQuarter_cubeSize);
mMap.push_back(dummy);
}
entity& renderWindow::getCube(int ID) {
for (int c = 0; c < mMap.size(); c++) {
if (mMap[c].getID() == ID)
return mMap[c];
}
}
entity& renderWindow::getCubeAt(float x, float y) {//TO DO
return entity(-1, 0, 0);
}
vector<sf::VertexArray> renderWindow::loadCube(int cubeID) {
vector<sf::VertexArray> vertices;
vertices.push_back(sf::VertexArray());
vertices.push_back(sf::VertexArray());
vertices.push_back(sf::VertexArray());
vertices[0].setPrimitiveType(sf::Quads);
vertices[0].resize(4);
vertices[1].setPrimitiveType(sf::Quads);
vertices[1].resize(4);
vertices[2].setPrimitiveType(sf::Quads);
vertices[2].resize(4);
sf::Vector2f tv0 = sf::Vector2f(0, 0);
sf::Vector2f tv1 = sf::Vector2f(mCubeSize, 0);
sf::Vector2f tv2 = sf::Vector2f(mCubeSize, mCubeSize);
sf::Vector2f tv3 = sf::Vector2f(0, mCubeSize);
sf::Vector2f v0 = sf::Vector2f(getCube(cubeID).getPoint(0, 0), getCube(cubeID).getPoint(0, 1));
sf::Vector2f v1 = sf::Vector2f(getCube(cubeID).getPoint(1, 0), getCube(cubeID).getPoint(1, 1));
sf::Vector2f v2 = sf::Vector2f(getCube(cubeID).getPoint(2, 0), getCube(cubeID).getPoint(2, 1));
sf::Vector2f v3 = sf::Vector2f(getCube(cubeID).getPoint(3, 0), getCube(cubeID).getPoint(3, 1));
sf::Vector2f v4 = sf::Vector2f(getCube(cubeID).getPoint(4, 0), getCube(cubeID).getPoint(4, 1));
sf::Vector2f v5 = sf::Vector2f(getCube(cubeID).getPoint(5, 0), getCube(cubeID).getPoint(5, 1));
sf::Vector2f v6 = sf::Vector2f(getCube(cubeID).getPoint(6, 0), getCube(cubeID).getPoint(6, 1));
sf::Vector2f v7 = sf::Vector2f(getCube(cubeID).getPoint(7, 0), getCube(cubeID).getPoint(7, 1));
sf::Vector2f v8 = sf::Vector2f(getCube(cubeID).getPoint(8, 0), getCube(cubeID).getPoint(8, 1));
sf::Vector2f v9 = sf::Vector2f(getCube(cubeID).getPoint(9, 0), getCube(cubeID).getPoint(9, 1));
sf::Vector2f v10 = sf::Vector2f(getCube(cubeID).getPoint(10, 0), getCube(cubeID).getPoint(10, 1));
sf::Vector2f v11 = sf::Vector2f(getCube(cubeID).getPoint(11, 0), getCube(cubeID).getPoint(11, 1));
vertices[0][0] = sf::Vertex(v0, tv0);
vertices[0][1] = sf::Vertex(v1, tv1);
vertices[0][2] = sf::Vertex(v2, tv2);
vertices[0][3] = sf::Vertex(v3, tv3);
vertices[1][0] = sf::Vertex(v4, tv0);
vertices[1][1] = sf::Vertex(v5, tv1);
vertices[1][2] = sf::Vertex(v6, tv2);
vertices[1][3] = sf::Vertex(v7, tv3);
vertices[2][0] = sf::Vertex(v8, tv0);
vertices[2][1] = sf::Vertex(v9, tv1);
vertices[2][2] = sf::Vertex(v10, tv2);
vertices[2][3] = sf::Vertex(v11, tv3);
return vertices;
}
void renderWindow::drawCube(int cubeID) {
mWindow.draw(verticesSide1[cubeID], &mTextures[getCube(cubeID).getTexture(0)]);
mWindow.draw(verticesSide2[cubeID], &mTextures[getCube(cubeID).getTexture(1)]);
mWindow.draw(verticesSide3[cubeID], &mTextures[getCube(cubeID).getTexture(2)]);
}
//CUBE ACTION-------------------------------------------
entity.h
#pragma once
class entity {
public:
entity();
entity(int id, int type, int numlayer);
void addPoint(int nbPoints);
void addTexture(int numTexture);
//SETTERS
void setPoint(int numPoint, float x, float y);
void setTexture(int textureID, int numTexture);
//GETTERS
int getID();
float getPoint(int numPoint, int numIndex);//if numIndex = 0 -> x || if numIndex = 1 -> y
int getType();
int getNumLayer();
int getTexture(int numTexture);
private:
int mID;
int mType;
int mNumLayer;
vector<sf::Vector2u> mPoints;
vector<int> mTextures;
};
#include "entity.cpp"
entity.cpp
#pragma once
entity::entity() {
mID = 0;
mType = -1;
mNumLayer = 0;
}
entity::entity(int id, int type, int numlayer) {
mID = id;
mType = type;
mNumLayer = numlayer;
}
void entity::addPoint(int nbPoints) {
mPoints.clear();
int newSize = 0;
for (int p = 0; p < nbPoints; p++) {
newSize++;
}
mPoints = vector<sf::Vector2u>(newSize);
}
void entity::addTexture(int numTexture) {
mTextures.push_back(numTexture);
}
//SETTERS
void entity::setPoint(int numPoint, float x, float y) {
mPoints[numPoint].x = x;
mPoints[numPoint].y = y;
}
void entity::setTexture(int textureID, int numTexture) {
mTextures[textureID] = numTexture;
}
//GETTERS
int entity::getID() {
return mID;
}
float entity::getPoint(int numPoint, int numIndex) {
if (numIndex == 0)
return mPoints[numPoint].x;
else
return mPoints[numPoint].y;
}
int entity::getType() {
return mType;
}
int entity::getNumLayer() {
return mNumLayer;
}
int entity::getTexture(int numTexture) {
return mTextures[numTexture];
}
I've done a lot of test, too much, so I won't post them right now, but if you have any question, feel free to ask.
Here is the problem described in the title :
And here, screens with only one face displayed(in the same order in the code):
The only thing I don't understand is that a cube displayed alone work perfectly fine if you enter the coordinates manually. Even the extended ones. But the coordinates formula is ok... (I noticed that the cube n°50 for a 15x15 map with 64x64 cube display a rectangle 'infinite' in width)
If the texture is extended(maybe to the infinite), it suggest that the coordinates are continuously increasing somewhere ? Then, why the cubes are still well placed ?
Here are the assets(64*64 png) :
Directories : textures/test/
Not really an answer (as the code will be rewritten anyway) so few hints for the new code instead (some of them are already mentioned in the comments).
Tileset
In the final isometric engine use sprites. They are faster and support pixel art. For my purposes I use compilation of these two free to use tilesets (64x64):
outside tileset
medieval building tileset
Both are compatible. I compiled and edited them to suite the needs of my engine. So this is what I use (still work in progress):
White color 0x00FFFFFF means transparent. The sprite is not enough. I added info about the height of tile and rotations.
If you see first 4 tiles from upper left corner they all are the same thing rotated by 90 degrees. So all my tiles have index of 4 tiles (the 90 degree rotations) int rot[4]. This way I can rotate the whole map or just view. I compile the set so the rotations are next to each other. There are 3 options:
tile[ix].rot[]={ ix,ix,ix,ix }; where ix is tile without rotation (ground)
tile[ix].rot[]={ ix,ix+1,ix,ix+1 }; where ix is tile with 2 rotations (those 2 tiles with chunk of chopped tree in the middle right)
tile[ix].rot[]={ ix,ix+1,ix+2,ix+3 }; where ix is tile with 4 rotations (like the first tile)
The indexes are valid of coarse only for the first tile only, the others have the whole rot[] array rotated by 1 value from neighbor. Some rotations are invisible (see the wide trees) but the tile is still present to allow rotations.
The tile height is important for placing tiles while editing and also for automatic map generations.
I plan to add also A* map for each tile so I can use path finding or compute watter flows and more.
Map editor
I prefer 3D maps. with bigger resolution you need to properly select the viewed area for viewing to maximize performance. Also a good idea is to create hollow underground so the rendering is much faster (this can be also done virtually during rendering process without the need of updating map).
I recommend to code these features:
make ground hollow
make ground solid
random terrain (diamond & square)
filter out small holes and smooth edges (add the slope tiles to cubic ones)
tile editor
Apart from the obvious paint editor you should add also another features like:
floor <-> ceiling
left <-> right
front <-> back
divide large sprite into regular tiles
copy/merge/paste
adjust lighting after left <-> right mirror operation
They are really handy while compiling/editing tileset resources. As you can see my tileset has many of tiles not present in the source tilesets. They were created by these functions + some minor paint editing... The colored masks on the bottom of the tileset are used to mask out and properly combine parts of tiles to create the missing ones ... (you can take one side form one tile and other from other ...)
[Notes]
For more info/ideas have a look at some related Q/As:
Improving performance of click detection on a staggered column isometric grid
How to procedurally generate isometric map
And here my Standalone no install Win32 Demo:
demo v1.000
demo v1.034
In OpenGL, when you are creating a OpenGL texture manually, you can assign 4 types:
GL_REPEAT, GL_CLAMP_TO_EDGE, GL_CLAMP and GL_CLAMP_TO_BORDER
If you want to learn more from the openGL textures differences, take a look here. Basically, it extend the last pixel in a image to the rest of the reserved memory.
In order to solve your problem, try to load the texture, modifing the parameters. I don't know if sfml allow to do it with Texture.hpp header, in the reference appear setRepeated, try to set true to see if solve the problem. Other way, loadfromfile with a size sf::IntRect(0, 0, 32, 32) in example.
This code is not tested, but teorically, using OpenGL will work:
void renderWindow::loadTexture(sf::String folder, int numTexture)
{
if (mMemoryTexture.loadFromFile("textures/" + folder + "/" + to_string(numTexture) + ".jpg"))
mTextures.push_back(mMemoryTexture);
else
cout << "Texture n°" << numTexture << " as failed to load." << endl;
// Generate OpenGL Texture manually
GLuint texture_handle;
glGenTextures(1, &texture_handle);
// Attach the texture
glBindTexture(GL_TEXTURE_2D, texture_handle);
// Upload to Graphic card
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
mMemoryTexture.GetWidth(), mMemoryTexture.GetHeight(),
0,
GL_RGBA, GL_UNSIGNED_BYTE, mMemoryTexture.GetPixelsPtr()
);
// Set the values
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
Maybe this helps you to solve your problem.
I endend by finding better way to do this code, thanks to members of stackoverflow. For people who got there by looking for a solution to a similar problem, I invite you to look at the comments for some usefull links and comment.

2D water shader in SFML

I want to implement the algorithm for a 2D water surface described here and here.
But instead of using two int arrays and calculating on the CPU I would like to use SFML's sf::RenderTexture's (FBO's basically) and a GLSL shader to run everything on the GPU. I want to use SFML, because it's so simple and I have worked with it before, so I know my way around it a little.
I've made some good progress so far. I was able to set up 3 sf::RenderTextures and ping-pong between them correctly (because other than int array you can't read and write to the same sf::RenderTexture at the same time). I was also able to adapt the algorithm for the height field creation form being in the range -32.767 to 32.767 to the range 0 to 1 (or to be more precise -0.5 to 0.5 for the calculation). Also adding new ripples works to some extend. So up to this point you can actually see a little of waves going on.
Here comes my problem now: The waves disappear really, really fast and I don't even apply any damping yet. According to the algorithm the ripples are not stopping if there is no damping applied. It's even the other way around. If I apply "amplification" the waves look close to what you would expect them to look like (but they still disappear without any damping applied to them). My first thought was that this is, because I use float's in range 0 - 1 instead of integers, but I only see this being a problem if multiplication is used, but I only use addition and subtraction.
Here is my SFML C++ code :
#include <SFML/Graphics.hpp>
#include <iostream>
int main()
{
sf::RenderWindow window(sf::VideoMode(1000, 1000), "SFML works!");
window.setFramerateLimit(12);
sf::RenderTexture buffers[3];
buffers[0].create(500, 500);
buffers[1].create(500, 500);
buffers[2].create(500, 500);
sf::RenderTexture* firstBuffer = buffers;
sf::RenderTexture* secondBuffer = &buffers[1];
sf::RenderTexture* finalBuffer = &buffers[2];
firstBuffer->clear(sf::Color(128, 128, 128));
secondBuffer->clear(sf::Color(128, 128, 128));
finalBuffer->clear(sf::Color(128, 128, 128));
sf::Shader waterHeightmapShader;
waterHeightmapShader.loadFromFile("waterHeightmapShader.glsl", sf::Shader::Fragment);
sf::Sprite spritefirst;
spritefirst.setPosition(0, 0);
spritefirst.setTexture(firstBuffer->getTexture());
sf::Sprite spritesecond;
spritesecond.setPosition(500, 0);
spritesecond.setTexture(secondBuffer->getTexture());
sf::Sprite spritefinal;
spritefinal.setPosition(0, 500);
spritefinal.setTexture(finalBuffer->getTexture());
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
window.close();
if(event.type == sf::Event::KeyReleased && event.key.code == sf::Keyboard::Escape)
window.close();
}
waterHeightmapShader.setParameter("mousePosition", sf::Vector2f(-1.f, -1.f));
// if mouse button is pressed add new ripples
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i mousePosition = sf::Mouse::getPosition(window);
if(mousePosition.x < 500 && mousePosition.y < 500)
{
sf::Vector2f mouse(mousePosition);
mouse.x /= 500.f;
mouse.y /= 500.f;
mouse.y = 1 - mouse.y;
std::cout << mouse.x << " " << mouse.y << std::endl;
waterHeightmapShader.setParameter("mousePosition", mouse);
}
}
waterHeightmapShader.setParameter("textureTwoFramesAgo", firstBuffer->getTexture());
waterHeightmapShader.setParameter("textureOneFrameAgo", secondBuffer->getTexture());
// create the heightmap
secondBuffer->display();
finalBuffer->clear(sf::Color(128, 128, 128));
finalBuffer->draw(sf::Sprite(secondBuffer->getTexture()), &waterHeightmapShader);
finalBuffer->display();
spritefirst.setTexture(firstBuffer->getTexture());
spritesecond.setTexture(secondBuffer->getTexture());
spritefinal.setTexture(finalBuffer->getTexture());
window.clear();
window.draw(spritefirst);
window.draw(spritesecond);
window.draw(spritefinal);
window.display();
// swap the buffers around, first becomes second, second becomes third and third becomes first
sf::RenderTexture* swapper = firstBuffer;
firstBuffer = secondBuffer;
secondBuffer = finalBuffer;
finalBuffer = swapper;
}
return 0;
}
And here is my GLSL shader code :
uniform sampler2D textureTwoFramesAgo;
uniform sampler2D textureOneFrameAgo;
uniform vec2 mousePosition;
const float textureSize = 500.0;
const float pixelSize = 1.0 / textureSize;
void main()
{
// pixels position
vec2 position = gl_TexCoord[0].st;
vec4 finalColor = ((texture2D(textureOneFrameAgo, vec2(position.x - pixelSize, position.y)) +
texture2D(textureOneFrameAgo, vec2(position.x + pixelSize, position.y)) +
texture2D(textureOneFrameAgo, vec2(position.x, position.y + pixelSize)) +
texture2D(textureOneFrameAgo, vec2(position.x, position.y - pixelSize)) - 2.0) / 2) -
(texture2D(textureTwoFramesAgo, position) - 0.5);
// damping
// finalColor.rgb *= 1.9; // <---- uncomment this for the "amplifiction" ie. to see the waves better
finalColor.rgb += 0.5;
// add new ripples
if(mousePosition.x > 0.0)
{
if(distance(position, mousePosition) < pixelSize * 5)
{
finalColor = vec4(0.9, 0.9, 0.9, 1.0);
}
}
gl_FragColor = finalColor;
}
Please remember that this is all just about the height field creation. There is no shading of the water yet.
Do you know why the waves disappear by them self without damping?
If I am reading the code correctly you sample the previous frame for the texture's colors/height and use four neighboring pixels/texels to determine the color/height of the current pixel.
As you are calculating (scaling) these neighbors you might run into missing the texel that contains the color/height you are looking for. It might not be the heighest texel, just one next to it a little bit lower causing the unexpected damping.
This is where you do not just use addition and subtraction:
const float pixelSize = 1.0 / textureSize;
By using this value you could just miss the texel you are looking for.
EDIT
Also: you are averaging the samples so the result will always be less than the maximum value of the samples. So instead of averaging you could select the maximum value. That might give weird results but also extra insight.
Here are some "Processing" codes which implements the same algorithm you've posted above, and its damping is correct, I hope you can get some points from it :
// codes begin
int Width = 800;
int Height = 600;
int FullSize = 0;
//int Spacing = 10;
int[] source, dest;
PImage bg;
void setup()
{
// if you want to run these codes by "Processing"
// please make a picture named "HelloWorld.png"
bg = loadImage("HelloWorld.png");
Width = bg.width;
Height = bg.height;
FullSize = Width * Height;
size(Width, Height);
source = new int[FullSize];
dest = new int[FullSize];
for (int i=0; i< FullSize; i++)
source[i] = dest[i] = 0;
}
void draw()
{
for (int i=Width; i< FullSize-Width; i++)
{
// check for bounds
int xi = i % Width;
if ((xi==0) || (xi==Width-1)) continue;
dest[i] = (
((source[i-1]+
source[i+1]+
source[i-Width]+
source[i+Width]) >>1) ) -dest[i];
int dampFactor = 1000;
dest[i] -= (dest[i] >> dampFactor); // Damping - Quick divde by 32 (5 bits)
}
//image(bg, 0, 0);
loadPixels();
for (int i=Width; i< FullSize-Width; i++)
{
// check for bounds
int xi = i % Width;
if ((xi==0) || (xi==Width-1)) continue;
int xoffset = dest[i-1] - dest[i+1];
int yoffset = dest[i-Width] - dest[i+Width];
int offset = i+xoffset+yoffset*Width;
if (offset>0 && offset<FullSize)
{
// TODO: make better map
pixels[i] = bg.pixels[offset];
}
}
//bg.updatePixels();
updatePixels();
//swap
int[] temp = source;
source = dest;
dest = temp;
}
void mouseDragged()
{
if (mouseX > 0 && mouseX < Width && mouseY > 0 && mouseY < Height)
source[mouseY*Width+mouseX] = (int)random(50, 100);
}
void mousePressed()
{
// TODO: make a area pulse value, like a radius circle
if (mouseX > 0 && mouseX < Width && mouseY > 0 && mouseY < Height)
source[mouseY*Width+mouseX] = (int)random(50, 100);
}
// codes end