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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Kojay

Pages: 1 2 3 [4] 5 6 7
46
Feature requests / Re: Ostream operators << for SFML classes
« on: March 20, 2014, 09:33:45 am »
Without further ado:

namespace sf {

class Debug {
public:

    Debug (std::ostream& sink = std::cout):
        m_stream(sink)
    {

    }    

    template <typename T>
    Debug& operator<<(const sf::Vector2<T>& vector) {
        m_stream << "Vector(" << vector.x << ", " << vector.y << ")\n";
        return *this;
    }

    template <typename T>
    Debug& operator<<(const sf::Rect<T>& rect) {
        m_stream << "Rect(" << rect.left << ", " << rect.top << ", " << rect.width << ", " << rect.height << ")\n";
        return *this;
    }

    Debug& operator<<(const sf::Transform& transform) {
        const float* matrix = transform.getMatrix();
        m_stream << "Transform:\n";
        for (int i=0; i<4; ++i){
            m_stream << "( ";
            for (int j=0; j<4; ++j)
                m_stream << matrix[i*4 + j] << " ";
            m_stream << ")\n";
        }
        return *this;
    }

    Debug& operator<<(const sf::Sprite& sprite) {
        m_stream << "Sprite: ";
        operator<<(sprite.getGlobalBounds());
        return *this;
    }

    ~Debug() {
        m_stream.flush();
    }

private:
    std::ostream& m_stream;

};

Debug debug(std::ostream& sink = std::cout) {
    return Debug(sink);
}

}
 

(Four operators implemented for demonstration purposes)
Drawback: cannot be used to output built-in or non-sfml types

Example usage:

sf::debug() << sf::Vector2f(10, 10) << sf::Vector2f(20, 20); //output to cout by default

sf::Sprite sprite;
sf::debug(std::cerr) << sprite << sprite.getTransform(); //outputs to cerr
 

Output:
Code: [Select]
Vector(10, 10)
Vector(20, 20)
Sprite: Rect(0, 0, 0, 0)
Transform:
( 1 0 0 0 )
( -0 1 0 0 )
( 0 0 1 0 )
( 0 0 0 1 )

It's easy to have it output to a fstream or stringstream instead.
The ctor is public so the user can make a persistent Debug object if they wish.

Quote
why on earth would someone ever want to save a whole sprite, or even worse a texture directly to a file?

Not the point.

47
Feature requests / Re: Ostream operators << for SFML classes
« on: March 19, 2014, 07:08:09 pm »
I don't think this is possible to do. Serializing something to a stream means to choose a format. And there's not a single good solution to this choice. Should we just serialize members directly so that we can use it to output stuff to binary files or network? Or should we do some pretty formatting for debugging purpose?

My proposal concerns the latter - pretty output for debugging purposes. The choice issue can be tackled by mimicking Qt; that is a sfDebug() class (albeit lighter than qDebug) that can be used similarly to a std::ostream and will not interfere with the operators written by the user. This can also be automatically left out of release builds, as well as allow the user to easily redirect the output.

Quote
By the way, if you write  operators << you have to provide operators >> as well, and things are even worse with them (parsing is a lot more complex than printing)

Quote
t feels unintuitive if there's no counterpart. When overloading operators, you should go for the principle of least surprise ("do as the ints do"); that's a commonly accepted convention in C++. Otherwise, named functions are often better suited.

I 'm not aware of this convention applying to these operators; surely input and output are distinct enough that once can conceive meaning for one but not the other.

To be clear, I think SFML is very intuitive to use and believe providing pretty output for its classes to be in this spirit.

So that we 're not talking about thin air, I will post an example of this sfDebug() class later.

48
Feature requests / Ostream operators << for SFML classes
« on: March 19, 2014, 04:51:38 pm »
I propose that SFML provides ostream operators for its classes to make for easier debugging (like Qt does - but not necessarily all the features of qDebug).

The chief design question in my view is whether those should be provided in a single header or along with each class. The ones for Vector and Rect would be presumably templated and have to be in a header, while the rest could be implemented in the source files.

49
The famous Separating Axis algorithm for determining intersection between arbitrary sf::Shapes:

bool intersect(const sf::Shape& shape_1, const sf::Shape& shape_2) {
    if (existsSeparatingAxisForFirst(shape_1, shape_2))
        return false;

    return (!existsSeparatingAxisForFirst(shape_2, shape_1));
}
 

The functions it is implemented in terms of:

sf::Vector2f getPoint(const sf::Shape& shape, unsigned int index) {
    return shape.getTransform().transformPoint(shape.getPoint(index));
}

sf::Vector2f projectShapeOn(const sf::Shape& shape, const sf::Vector2f& axis) {

    auto point = getPoint(shape, 0);
    auto initial = dotProduct(point, axis);

    sf::Vector2f minmax(initial, initial);

    for (unsigned int i=1; i<shape.getPointCount(); ++i){
        auto point = getPoint(shape, i);
        auto projected = dotProduct(point, axis);

        if (projected < minmax.x)
            minmax.x = projected;
        if (projected > minmax.y)
            minmax.y = projected;
    }

    return minmax;
}

bool existsSeparatingAxisForFirst(const sf::Shape& shape_1, const sf::Shape& shape_2) {
    unsigned int pointCount = shape_1.getPointCount();

    for (unsigned int i=0; i<pointCount; ++i){
        unsigned int next_i = (i + 1) % pointCount;
        auto side = getPoint(shape_1, next_i) - getPoint(shape_1, i);
        auto perpendicular = unitVector(perpendicularVector(side));
        auto minmax_1 = projectShapeOn(shape_1, perpendicular);
        auto minmax_2 = projectShapeOn(shape_2, perpendicular);

        if ((minmax_1.y < minmax_2.x) || (minmax_2.y < minmax_1.x))
            return true;
    }

    return false;
}
 

A simple example:


Arrows to move current shape, W,A,S,D to rotate it, Q,E,Z,C to scale it.
Spacebar to cycle through shapes.
Shapes are red when they don't intersect with any other. They turn green if they intersect with at least one other shape.

Source for this example at:

https://gist.github.com/Kojirion/9635598

(For convenience, vector math functions are included; they are similar to those provided by Thor)

A few notes, possibly to be addressed in the future:

- The algorithm can not be applied to sprites at the moment; it should be easy to accomplish this with a Facade.
- It is assumed the Shape is convex (as stated in the SFML docs), there are no checks that this is so.
- Points are transformed twice. Caching the results would likely improve performance.

Edit: Changed title from "Pixel perfect collision detection" so as not to imply this is a mask based algorithm.

50
General discussions / Re: Unit Testing
« on: February 06, 2014, 08:02:54 am »
The benefits of TDD are well established. On the other hand, I 'm sceptical/unclear on how one is meant to aim for 100% coverage when developing a game, due to visual aspect. How do you verify that what you mean to draw really is drawn? As in gui design, running the application as a user is a far more straightforward way to test (by the way, correct me if I 'm wrong Tank but SFGUI doesn't got a test suite; instead the examples are used as tests).

Incidentally, there is a new version of Boost.Test that only requires docs to make it to release - though I have not tried it and don't believe it would make use of C++11.

51
General / Re: Help with Tile Map tutorial
« on: January 26, 2014, 10:08:23 pm »
Quote
Using algorithms was not required

Besides the point; all STL algorithms can be hand-written.

Quote
KISS
Yes, using the STL makes for far simpler and more robust code than the obscurities individual programmers come up with.

52
General / Re: Help with Tile Map tutorial
« on: January 25, 2014, 09:57:22 pm »
I just need to find a way to store the values in a text file into a vector array (in this case vector<int>)

This does the trick:

std::vector<int> tiles;
std::ifstream map_stream("map.txt");
std::copy(std::istream_iterator<int>(map_stream), std::istream_iterator<int>(), std::back_inserter(tiles));
 

However, it means the number of columns will still be hardcoded.

std::copy is an algorithm copying the given range (defined by the first two parameters, which are two iterators) to the one supplied by the third parameter.
The istream_iterators specify a range covering the input stream of the text file
std::back_inserter(tiles) will append elements at the end of tiles - effectively the same as invoking push_back in a hand-written loop.

Yes it's fancy; you still have to help yourself.

i) if Lignum's function return a vector and you want one returning a boolean, write both and have the latter call the former
ii) The map's location doesn't got anything to do with the other parameters. If you wish to pass it, pass it.

This isn't a diary to blabber on about wants and needs nor is it a place to lay out requirements, unless you mean to hire us.

53
General / Re: Help with Tile Map tutorial
« on: January 24, 2014, 04:52:06 pm »
          in.close(); // Free resources. This is important! We don't want any memory leaks.
 

Do I need to manually close a ifstream?

Given a text file such as this:

Code: [Select]
0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 0 0 0 0 2 0 0 0 0
1 1 0 0 0 0 0 0 3 3 3 3 3 3 3 3
0 1 0 0 2 0 3 3 3 0 1 1 1 0 0 0
0 1 1 0 3 3 3 0 0 0 1 1 1 2 0 0
0 0 1 0 3 0 2 2 0 0 1 1 1 1 2 0
2 0 1 0 3 0 2 2 2 0 1 1 1 1 1 1
0 0 1 0 3 2 2 2 0 0 0 0 1 1 1 1

The following will read from it (it is the same as the tutorial example, except that it reads from a file instead of an array):

#include <SFML/Graphics.hpp>
#include <fstream>
#include <iterator>
#include <sstream>

class TileMap : public sf::Drawable, public sf::Transformable
{
public:

    bool load(const std::string& tileset, sf::Vector2u tileSize)
    {
        // load the tileset texture
        if (!m_tileset.loadFromFile(tileset))
            return false;

        std::vector<std::vector<int> > tiles;
        std::ifstream map_stream("map.txt");
        for (std::string line; std::getline(map_stream, line);){
            tiles.push_back(std::vector<int>());
            std::stringstream line_stream(line);
            std::copy(std::istream_iterator<int>(line_stream), std::istream_iterator<int>(), std::back_inserter(tiles.back()));
        }

        unsigned int height = tiles.size();

        m_vertices.setPrimitiveType(sf::Quads);


        // populate the vertex array, with one quad per tile
        for (unsigned int j = 0; j < height; ++j){
            unsigned int width = tiles[j].size();
            for (unsigned int i = 0; i < width; ++i)
            {
                // get the current tile number
                int tileNumber = tiles[j][i];

                // find its position in the tileset texture
                int tu = tileNumber % (m_tileset.getSize().x / tileSize.x);
                int tv = tileNumber / (m_tileset.getSize().x / tileSize.x);

                // get a pointer to the current tile's quad
                sf::Vertex quad[4];

                // define its 4 corners
                quad[0].position = sf::Vector2f(i * tileSize.x, j * tileSize.y);
                quad[1].position = sf::Vector2f((i + 1) * tileSize.x, j * tileSize.y);
                quad[2].position = sf::Vector2f((i + 1) * tileSize.x, (j + 1) * tileSize.y);
                quad[3].position = sf::Vector2f(i * tileSize.x, (j + 1) * tileSize.y);

                // define its 4 texture coordinates
                quad[0].texCoords = sf::Vector2f(tu * tileSize.x, tv * tileSize.y);
                quad[1].texCoords = sf::Vector2f((tu + 1) * tileSize.x, tv * tileSize.y);
                quad[2].texCoords = sf::Vector2f((tu + 1) * tileSize.x, (tv + 1) * tileSize.y);
                quad[3].texCoords = sf::Vector2f(tu * tileSize.x, (tv + 1) * tileSize.y);

                for (int k=0; k<4; ++k)
                    m_vertices.append(quad[k]);
            }
        }
        return true;
    }

private:

    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        // apply the transform
        states.transform *= getTransform();

        // apply the tileset texture
        states.texture = &m_tileset;

        // draw the vertex array
        target.draw(m_vertices, states);
    }

    sf::VertexArray m_vertices;
    sf::Texture m_tileset;
};

int main()
{
    // create the window
    sf::RenderWindow window(sf::VideoMode(512, 256), "Tilemap");

    // create the tilemap from the level definition
    TileMap map;
    if (!map.load("tileset.png", sf::Vector2u(32, 32)))
        return -1;

    // run the main loop
    while (window.isOpen())
    {
        // handle events
        sf::Event event;
        while (window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        // draw the map
        window.clear();
        window.draw(map);
        window.display();
    }

    return 0;
}
 

No information about the map's dimensions is hardcoded. In fact, it is possible for some lines to have fewer elements and it will still work.

54
General / Re: sf::Vector2f per value or const reference
« on: January 15, 2014, 12:30:07 pm »
A bit late, but I haven't gotten around to making an example the assembly output of which I could examine, as I was hoping for. Nonetheless:

sf::Vector is not POD therefore copying it is not supposed to be the same as the bitwise copy of double.

Furthermore, if one's in the habit of always passing non built-ins by  reference, the code is not any less readable (on the contrary, passing by copy makes it stand out). And presumably the editor highlights const differently so the type still stands out.

edit 20/1:
a simple bechmark:

#include <SFML/System/Vector2.hpp>
#include <boost/timer/timer.hpp>
#include <vector>

void copy(sf::Vector2f vector) {
}

void reference(const sf::Vector2f& vector){
}


int main()
{

    std::vector<sf::Vector2f> vectors(1000000);

    {
        boost::timer::auto_cpu_timer t;
        for (const auto& vector : vectors)
            copy(vector);
    }



    {
        boost::timer::auto_cpu_timer t;
        for (const auto& vector : vectors)
            reference(vector);
    }

    return 0;
}
 

Compiled by g++ without optimization; passing by reference comes out 1ms faster on average.

55
General discussions / Re: Mutual following on Twitter!
« on: January 10, 2014, 04:27:56 pm »
Never thought I 'd see the day... @Kojirion_H

56
SFML wiki / Application class (using sfml, sfgui and thor)
« on: January 02, 2014, 09:19:17 pm »
Hello,

in several projects now I have used these 3 libraries as a sort of lightweight gui framework, with the emphasis on graphical drawing on a canvas. The boilerplate code is contained within the following class:

#include <SFML/Window.hpp>
#include <Thor/Input/ActionMap.hpp>
#include <Thor/Input/EventSystem.hpp>
#include <SFGUI/SFGUI.hpp>

typedef thor::ActionMap<std::string> ActionMap;
typedef ActionMap::CallbackSystem CallbackSystem;

class Application
{
public:
    Application();
    void run();

private:
    sfg::SFGUI sfgui;
    sf::Window window;
    sfg::Desktop desktop;
    sf::Image icon;
    ActionMap actions;
    CallbackSystem system;
};
 
#include "Application.hpp"

Application::Application():
    window(sf::VideoMode(800, 600), "Application")
{
    if (icon.loadFromFile(""))
        window.setIcon(icon.getSize().x, icon.getSize().y, icon.getPixelsPtr());

    window.setFramerateLimit(60);

    actions["Close"] = thor::Action(sf::Event::Closed);
    system.connect("Close", std::bind(&sf::Window::close, &window));
}

void Application::run()
{
    sf::Clock clock;

    while (window.isOpen()){

        actions.clearEvents();

        sf::Event event;
        while (window.pollEvent(event)){
            actions.pushEvent(event);
            desktop.HandleEvent(event);
        }

        actions.invokeCallbacks(system, &window);
        desktop.Update(clock.restart().asSeconds());

        sfgui.Display(window);
        window.display();
    }
}
 

Note that sfml drawing can be done on a sfg::Canvas, therefore a sf::RenderWindow is not required.
Comments welcome.

57
Feature requests / Re: Getting a sprite's vertices
« on: December 22, 2013, 05:12:07 pm »
No indeed, the Sprite I wrote about above is not sf::Sprite - that's the alternate proposal, a similar class.

Quote
And exactly these functions are already implemented in sf::Sprite, therefore a solution should aim at reusing them where possible.
Which was what prompted me to post in the first place.

Just to be sure we 're on the same page, here's a quick example:

#include <SFML/Graphics.hpp>
#include <array>

class Sprite {
public:
    Sprite(const sf::Vector2f& position) {
        const float side = 50.f;

        vertices[0].position = position;
        vertices[1].position = position + sf::Vector2f(side, 0);
        vertices[2].position = position + sf::Vector2f(side,side);
        vertices[3].position = position + sf::Vector2f(0, side);
    }

    void appendTo  (sf::VertexArray& array) {
        for (const auto& vertex : vertices)
            array.append(vertex);
    }

private:
    std::array<sf::Vertex, 4> vertices;
};



int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 800), "Sprites");

    std::vector<Sprite> sprites;

    for (int i=0; i<8; ++i)
        sprites.emplace_back(sf::Vector2f(i*100, i*100));

    sf::VertexArray toDraw(sf::Quads);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        //update
        toDraw.clear();
        for (auto& sprite : sprites)
            sprite.appendTo(toDraw);

        //draw
        window.clear();
        window.draw(toDraw);
        window.display();
    }

    return 0;
}
 

I don't see this as any more cumbersome than iterating through a structure of sf::Drawables.

58
Feature requests / Re: Getting a sprite's vertices
« on: December 22, 2013, 04:16:23 pm »
It could be simply

class Sprite {
public:
        void setTextureRect(const sf::IntRect& rectangle);
        void setColor(const sf::Color& color);
        sf::FloatRect getBounds() const;
        void appendTo(const sf::VertexArray& array) const;
        void appendTo(OutputIterator result)
}
 

Since a transform would be applied to the vertices rather than the RenderStates, it may pay to keep the class suited for sprites that aren't meant to be scaled or rotated (such as the aforementioned tilemaps, also sprites that achieve change of facing by shifting the texture rect rather than being rotated); in which case a setter for position would be sufficient.

Quote
There is no reason to use vertex arrays for every single character in the game, especially not if they use different textures

Even if the textures could be concatenated? I can see the benefit of sf::Sprite for prototyping, however achieving maximum performance would always be on my todo list.

59
Feature requests / Re: Getting a sprite's vertices
« on: December 21, 2013, 11:39:50 am »
By the same argument, the user could put together sf::Sprite themselves. Not to mention, that makes a lot of helper classes that got to be ditched as soon as one gets serious - that is not redundant?

An alternate proposal for either SFML or Thor would be a similar class designed precisely to that end, namely batching sprites together. It doesn't get in the way of the user's customized solution - getVertices() or appendTo() is only called if the sprite has been determined to be visible, whatever the means employed.

60
SFML projects / Re: 'Tiled' Tile-map Loader
« on: December 20, 2013, 12:52:24 am »
Going through the code, it is not clear that vertex arrays are taken advantage of to draw each layer in a single call. As far as I can tell, each tile is represented by a sprite and each of those is drawn individually. Instead, each tile should only hold 4 sf::Vertex; in the draw function, if the tile is visible, then append its vertices to the vertex array to be drawn.

Pages: 1 2 3 [4] 5 6 7