Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Weird texturing issue  (Read 3186 times)

0 Members and 1 Guest are viewing this topic.

Cl9

  • Newbie
  • *
  • Posts: 21
    • View Profile
    • Email
Weird texturing issue
« on: February 27, 2014, 05:49:00 pm »
Hey, over the past few days I've been writing a small engine to render blocks to the screen along with lighting but I've encountered a weird bug which causes a block after several animated blocks to become glitched:





I really can't find what's causing the problem and it's annoying me quite a bit...

Here's the source (it's quite messy):

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <fstream>
#include <sstream>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
using namespace std;
int nolight = 0;
//String to int conversion function
int StringToInt(string Number)
{
    return atoi(Number.c_str());
}
//Int to string conversion function
template <typename T>
string IntToString ( T Number )
{
    ostringstream ss;
    ss << Number;
    return ss.str();
}

struct Position //A position struct for handling all variables to do with position
{
    int x = 0, y = 0;
};

struct WindowSettings //A structure for holding window settings such as its name and size
{
    const string windowName = "Test";
    const int Width = 1024; //32 across
    const int Height = 512; //16 up
};


class PlayerClass //The player class for handling the player
{
private:
    int Health = 0; //Player health variable
    int x = 0, y = 0; //Player position variables (x,y)
public:
    void setHealth(int Health); //Setting player health
    int getHealth(); //Getting player health
    void setPosition(Position NewPosition); //Set the players position using position struct.
    Position getPosition(); //Get the players position using position struct
};

void PlayerClass::setHealth(int NewHealth) //Setting player health
{
    Health = NewHealth;
}

int PlayerClass::getHealth() //Getting player health
{
    return Health;
}

Position PlayerClass::getPosition() //Get the players position
{
    Position ReturnValue;
    ReturnValue.x = x;
    ReturnValue.y = y;
    return ReturnValue;
}

void PlayerClass::setPosition(Position NewPosition) //Set the players position
{
    x = NewPosition.x;
    y = NewPosition.y;
}
class MapClass //Class for handling the map, blocks and textures etc.
{
private:
    WindowSettings WINDOW_SETTINGS;
    vector<bool> isVisible; //Decides if a block should be rendered or not
    vector<sf::RectangleShape> Blocks; //A vector to hold the block shapes
    vector<double> heightMap; //A heightmap to decide what height mobs/the player should be on it
    vector<sf::Texture> blockTextures; //A vector for holding block textures
    vector<string> loadedTextures; //A vector containing all loaded textures to prevent them from being loaded multiple times
    vector<int> BlockHeights; //Block heights for heightmap calculation
    vector<int> BlockWidths; //Block widths for heightmap calculation
    vector<int> TextureID; //A reference to the ID of the texture used on a block
    vector<string> TextureFP;
    vector<sf::Clock> AnimationClock;
    vector<sf::Time> AnimationSwitchTime;
    vector<int> animatedBID;
    vector<int> AnimationPhase;
    vector<int> MaxAnimationPhase;
    vector<int> MinAnimationPhase;
    vector<sf::Time> CurrentAnimationTime;
    vector<bool> Animated; //True/false depending on if the block is animated
public:
    sf::RectangleShape *BlockReference(int BlockID);
    int loadTexture(string FileName); //A function for loading textures into memory
    void setVisibility(int BlockID, bool Visible); //Setting a block to render/not render
    int setBlockTexture(string Texturename, int BlockID); //Texture a block
    int createBlock(bool Visibility, string FileName, int Height, int Width, bool Animated, sf::Time AnimationSwitchTime,int StartPhase, int MaxPhase); //Create a new block
    void setBlockPos(int BlockID, Position BlockPosition); //Set a blocks position
    Position getBlockPos(int BlockID); //Return a blocks position in a POSITION structure.
    bool isBlockVisible(int BlockID); //Returns true if a block is visible, false if the block is not
    bool loadMap(string FilePath); //Loads a map automatically, creates all of the blocks, entity's and lights.
    int BlockCount(); //Returns number of loaded blocks
    void updateAnimatedBlocks();
    void reTextureBlocks();
};
int MapClass::BlockCount()
{
    return isVisible.size();
}
sf::RectangleShape *MapClass::BlockReference(int BlockID)
{
    return &Blocks[BlockID];
}
void MapClass::reTextureBlocks()
{
    for(int a = 0; a < (int)Blocks.size(); a++)
    {
        Blocks[a].setTexture(&blockTextures[TextureID[a]]);
    }
}
int MapClass::loadTexture(string FileName) //Load a texture into memory
{
    for(int a = 0; a < (int)loadedTextures.size(); a++)
    {
        if(loadedTextures[a] == FileName)
        {
            return a; //If the texture is already loaded then return that textures ID
        }
    }


    blockTextures.push_back(sf::Texture());
    if (!blockTextures[blockTextures.size()-1].loadFromFile(FileName+".png"))
    {
        cout << "\nCould not load block texture!" << endl;
        blockTextures.pop_back();
        return -1;
    }
    loadedTextures.push_back(FileName);
    for(int a = 0; a < (int)Blocks.size(); a++)
    {
        Blocks[a].setTexture(&blockTextures[TextureID[a]]);
    }
    return blockTextures.size()-1;
}
void MapClass::setVisibility(int BlockID, bool Visible) //Set a blocks visibility to true/false
{
    if(!BlockID > isVisible.size())
    {
        if(Visible)
            isVisible[BlockID] = true;
        else
            isVisible[BlockID] = false;
    }
}

int MapClass::setBlockTexture(string Texture, int BlockID) //Set a blocks texture to something
{
    int TextureID2 = loadTexture(Texture);
    Blocks[BlockID].setTexture(&blockTextures[TextureID2]);
    return TextureID2;
}

Position MapClass::getBlockPos(int BlockID)
{
    Position BP;
    BP.x = Blocks[BlockID].getPosition().x;
    BP.y = Blocks[BlockID].getPosition().y;
    return BP;
}

bool MapClass::isBlockVisible(int BlockID)
{
    if(!isVisible[BlockID])
    {
        return false;
    }
    Position BlockPosT;
    BlockPosT = getBlockPos(BlockID);
    if((BlockPosT.x > WINDOW_SETTINGS.Width && BlockPosT.x > WINDOW_SETTINGS.Width - BlockWidths[BlockID]) || (BlockPosT.x < 0 && BlockPosT.x < Blocks[BlockID].getPosition().x + BlockWidths[BlockID]))
    {
        if((BlockPosT.y > WINDOW_SETTINGS.Height && BlockPosT.y > WINDOW_SETTINGS.Height - BlockHeights[BlockID]) || (BlockPosT.y < 0 && BlockPosT.y < Blocks[BlockID].getPosition().y + BlockHeights[BlockID]))
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    else
    {
        return true;
    }

}

int MapClass::createBlock(bool Visible, string TextureName, int Height, int Width, bool AnimatedS, sf::Time SwapTime,int StartPhase, int MaxPhase) //Create a new block and set its texture
{
    TextureFP.push_back(TextureName);
    TextureID.push_back(0);
    isVisible.push_back(Visible);
    Blocks.push_back(sf::RectangleShape(sf::Vector2f(Height,Width)));
    BlockHeights.push_back(Height);
    BlockWidths.push_back(Width);
    int id = setBlockTexture(TextureName, Blocks.size()-1);
    TextureID[Blocks.size()-1] = id;
    setBlockTexture(TextureName, Blocks.size()-1);
    Animated.push_back(AnimatedS);
    if(AnimatedS == true)
    {
        AnimationClock.push_back(sf::Clock());
        AnimationSwitchTime.push_back(sf::Time(SwapTime));
        CurrentAnimationTime.push_back(sf::Time());
        animatedBID.push_back(Blocks.size()-1);
        AnimationPhase.push_back(0);
        MaxAnimationPhase.push_back(MaxPhase);
        MinAnimationPhase.push_back(StartPhase);
    }
    return Blocks.size()-1;

}

void MapClass::setBlockPos(int BlockID, Position NewPos) //Set a blocks position
{
    Blocks[BlockID].setPosition(NewPos.x, NewPos.y);
}

MapClass Map; //In charge of map management
class LightingClass //Manage block lighting
{
private:
    int lightLevel = 0;
    vector<Position> lightPos;
    vector<int> lightStrengh;
public:
    int getLightLevel();
    void setLightLevel(int Level);
    int calculateLighting(int BlockID);
    void addLight(Position LightPosition, int LightLevel);
};

void LightingClass::addLight(Position LightPos, int LL)
{
    lightPos.push_back(LightPos);
    lightStrengh.push_back(LL);
}
int LightingClass::calculateLighting(int Bid)
{
    int closestLightDistance = 99999999;
    int tempDistance = 0;
    Position blockpos = Map.getBlockPos(Bid);
    int ClosestLightID = 0;

    for(int b = 0; b < (int)lightPos.size(); b++)
    {
        tempDistance = (std::abs(blockpos.x - lightPos[b].x) + std::abs(blockpos.y - lightPos[b].y));
        if(tempDistance < closestLightDistance)
        {
            closestLightDistance = tempDistance;
            ClosestLightID = b;
        }
    }
    if(closestLightDistance <= 128)
    {
        int LightDensity = 0;
        if(closestLightDistance <= 32)
        {
            LightDensity = 120+(lightStrengh[ClosestLightID]*4);
        }
        else if(closestLightDistance <= 64)
        {
            LightDensity = 80+(lightStrengh[ClosestLightID]*4);
        }
        else if(closestLightDistance <= 96)
        {
            LightDensity = 60+(lightStrengh[ClosestLightID]*2);
        }
        else if(closestLightDistance <= 128)
        {
            LightDensity = 40+(lightStrengh[ClosestLightID]*2);
        }
        return LightDensity;
    }
    return 20; //Return a black value by default if the block is not within light range of an object
}
void LightingClass::setLightLevel(int ll)
{
    lightLevel = ll;
}
int LightingClass::getLightLevel()
{
    return lightLevel;
}
LightingClass Lighting; //Handles block lighting
bool MapClass::loadMap(string FilePath)
{
    cout << "\nLoading " << FilePath << "... " << endl;
    ///Load the map file into memory
    ifstream File;
    string Buffer;
    string Line = "";
    vector<string> MapL;
    File.open(FilePath);
    if(File.is_open())
    {
        while(!File.eof()) //While there's data to read. Using eof doesn't matter here
        {
            getline(File, Line); //Get the file line and store it in line
            for(int charPos = 0; charPos < (int)Line.size(); charPos++)
            {
                if(Line[charPos] == ',') //Remove commas and split each into a vector
                {
                    MapL.push_back(Buffer);
                    Buffer = "";
                }
                else
                {
                    Buffer += Line[charPos];
                }


            }
        }
        MapL.push_back(Buffer); //Ensure that last line of the map is processed
        Buffer.clear(); //Clear the buffer
    }
    else
    {
        cout << "\nCould not find map: " << FilePath << endl;
        return false;
    }
    File.close();
    ///Process the map and register any blocks, light-sources or entity's
    bool blocksProcessed = false, lightsProcessed = false, entitysProcessed = false;
    int blockX = 0, blockY = 0; //Current block to create
    string TexturePath = "";
    Position blockpos;
    int bid = 0; //Temporarily stores the block id of a created block for placing
    for(int a = 0; a < (int)MapL.size(); a++)
    {
        if(blocksProcessed == false && lightsProcessed == false) //Load lights onto the screen
        {
                if(MapL[a] == "Blocks:")
                {
                    a++;
                    lightsProcessed = true;
                }
                else if(StringToInt((string)MapL[a]) == 1)
                {
                        int lightx = 0, lighty = 0, intensity = 0;
                        lightx = StringToInt((string)MapL[a+1]);
                        lighty = StringToInt((string)MapL[a+2]);
                        intensity = StringToInt((string)MapL[a+3]);
                        Position lightpos;
                        lightpos.x = lightx;
                        lightpos.y = lighty;
                        Lighting.addLight(lightpos, intensity);
                        a+=3;
                        nolight++;
                }
            }
        if(lightsProcessed == true && blocksProcessed == false) //Loads blocks onto the screen
        {
            sf::Time SwitchTime;
            TexturePath = "";
            blockpos.x = blockX, blockpos.y = blockY;
                switch(StringToInt((string)MapL[a]))
                {
                    case 0: //Air
                        break;
                    case 1: //stone
                        TexturePath = "blocks\\stone";
                        bid = Map.createBlock(true, TexturePath, 32 , 32, false, sf::Time(), 0,0);
                        break;
                    case 2: //water
                        TexturePath = "blocks\\water_still";
                        SwitchTime = sf::milliseconds(100);
                        bid = Map.createBlock(true, TexturePath, 32 , 32, true, SwitchTime, 1,16);
                        break;

                    case 3: //lava
                        TexturePath = "blocks\\lava_still";
                        SwitchTime = sf::milliseconds(100);
                        bid = Map.createBlock(true, TexturePath, 32 , 32, true, SwitchTime, 1,10);
                        break;
                    case 4: //grass
                        TexturePath = "blocks\\grass_side";
                        bid = Map.createBlock(true, TexturePath, 32 , 32, false, sf::Time(), 0,0);
                        break;
                }
            }
            if(TexturePath != "")
            {
                Map.setBlockPos(bid, blockpos);
            }

            blockX += 32;
            if(blockX == 1024)
            {
                blockY += 32;
                blockX = 0;
            }
            if(blockY == 512)
            {
                blockY = 0;
            }
    }
    return true;
}

void MapClass::updateAnimatedBlocks()
{
    for(int a = 0; a < (int)animatedBID.size(); a++)
    {
        CurrentAnimationTime[a] = AnimationClock[a].getElapsedTime();
        if(CurrentAnimationTime[a] >= AnimationSwitchTime[a])
        {
            if(AnimationPhase[a] >= MaxAnimationPhase[a]-1)
            {
                AnimationPhase[a] = MinAnimationPhase[a]-1;
            }
            else
            {
                AnimationPhase[a]++;
            }
            int yloc = AnimationPhase[a] * 32;
            sf::IntRect tsize(0, yloc, 32, 32); //Set the portion of the texture to be visible
            Blocks[animatedBID[a]].setTextureRect(tsize);
            setBlockTexture(TextureFP[animatedBID[a]], animatedBID[a]);
            AnimationClock[a].restart();
        }
    }
}

int main()
{
    PlayerClass Player; //In charge of player functions
    WindowSettings Settings; //Declares a structure containing details about the window

    //Creating our enviroment
    Map.loadMap("map.txt");
    if(nolight != 0)
    {
        for(int a = 0; a < Map.BlockCount(); a++)
        {
            int LightLevel = Lighting.calculateLighting(a);
            sf::RectangleShape& TempBlock = *Map.BlockReference(a);
            sf::Color bc = TempBlock.getFillColor();
            TempBlock.setFillColor(sf::Color(bc.r,bc.g,bc.b, LightLevel));
        }
    }

    sf::RenderWindow window(sf::VideoMode(Settings.Width,Settings.Height), Settings.windowName); //Creating the window
    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event)) //The event loop
        {
            if(event.type == sf::Event::Closed) //if window close button is pressed then:
            {
                window.close();
            }
        }
        window.clear(sf::Color::Black); //Clear the window with a black colour to erase previous frame
        for(int a = 0; a < Map.BlockCount(); a++)
        {
            Map.updateAnimatedBlocks();
            sf::RectangleShape &blockToDraw = *Map.BlockReference(a);
            window.draw(blockToDraw);
        }
        window.display(); //Finally display the window
    }
    return 0;
}

[/code=cpp]

The map file looks like this:

[code]
Blocks:,
2,2,2,2,2,2,2,4,4,4,4,4,4,
END_OF_FILE,
 

What's causing this?
Any help is appreciated - Cl9.
« Last Edit: February 27, 2014, 08:41:54 pm by Cl9 »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Weird texturing issue
« Reply #1 on: February 27, 2014, 06:50:05 pm »
I highly doubt anyone will go through your full code. It's way too long to quickly sweep through and it takes quite a bit of time and effort just to understand it.

You should isolate the problem further and you just might solve it on the way. Start using your debugger to find out what the states are, once the tiles misbehave. What part of your code is causing it? How did it get there? Are there any variables that get invalidated or over-/underflow?

Programming is not (only) hard, because of the code one needs to write, but because of the possible mistakes that can happen and the time required to hunt these bugs down.

If you can't find anything with just debugging, then it's time to uncomment portions of the code and observe whether it still happens. That way, you should be able to reduce your code, until you've only a main function and maybe one or two helper classes.

And if you're asking on the forum, you should provide more information than "[...] weird bug [...] blocks [...] become glitched." and then throw the whole source code at us. Describe what you want to do, what you expect to happen and what actually happens. And then go on into describing what you've already tried.

As a final point, if you post code, please put them inside the [ code=cpp ] tag. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Weird texturing issue
« Reply #2 on: February 27, 2014, 07:17:27 pm »
This really looks like a bad texture rect in Y direction. Double-check your animation frames.
Laurent Gomila - SFML developer

Cl9

  • Newbie
  • *
  • Posts: 21
    • View Profile
    • Email
Re: Weird texturing issue
« Reply #3 on: February 27, 2014, 08:34:55 pm »
Even whilst disabling the animation code it still does this though?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Weird texturing issue
« Reply #4 on: February 27, 2014, 08:48:32 pm »
You don't need an animation to have a bad texture rect ;)

If you want efficient answers, don't post walls of code, read this instead:
http://en.sfml-dev.org/forums/index.php?topic=5559.msg36368#msg36368
Laurent Gomila - SFML developer

Cl9

  • Newbie
  • *
  • Posts: 21
    • View Profile
    • Email
Re: Weird texturing issue
« Reply #5 on: February 27, 2014, 08:58:22 pm »
What can cause problems like this? Should I manually define the rect of the texture?

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Weird texturing issue
« Reply #6 on: February 27, 2014, 09:09:17 pm »
This really looks like a bad texture rect in Y direction. Double-check your animation frames.

Use a debugger and ensure that the texture rect is valid.
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Cl9

  • Newbie
  • *
  • Posts: 21
    • View Profile
    • Email
Re: Weird texturing issue
« Reply #7 on: February 27, 2014, 09:12:30 pm »
Unfortunately for some reason... the debugger in the code::blocks IDE does not work with the program, it launches it but the program never starts the GUI. I shall try downloading another debugger and trying that...

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Weird texturing issue
« Reply #8 on: February 27, 2014, 11:06:41 pm »
Everywhere you call setTextureRect, add this:
std::cout << rect.x << " " << rect.y << " " << rect.width << " " rect.height << std::endl;
Laurent Gomila - SFML developer

Njifra

  • Guest
Re: Weird texturing issue
« Reply #9 on: February 27, 2014, 11:30:57 pm »
Make sure that you havent load texture outside of texture rect.
For example, your texture file width is 64 and u set sprites  texture rect x position to 96.
Sorry for my bad english :/

Cl9

  • Newbie
  • *
  • Posts: 21
    • View Profile
    • Email
Re: Weird texturing issue
« Reply #10 on: February 28, 2014, 07:54:45 pm »
I've fixed the problem thanks, I've fixed the problem by using the setRect() function in the CreateBlock() class... I'm still unsure as to why it happened though thanks :)