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/
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.
0 comments:
Post a Comment