Tuesday, April 5, 2016

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

Leave a Comment

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 :

enter image description here

And here, screens with only one face displayed(in the same order in the code):

Side 1 only displayed

Side 2 only displayed

Side 3 only displayed

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) : enter image description hereenter image description hereenter image description here Directories : textures/test/

1 Answers

Answers 1

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.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment