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

Author Topic: problem with sf::RenderTexture::Draw in derived class  (Read 3291 times)

0 Members and 1 Guest are viewing this topic.

carsaxy

  • Newbie
  • *
  • Posts: 11
    • View Profile
problem with sf::RenderTexture::Draw in derived class
« on: December 23, 2011, 10:28:28 am »
Hi all.
I'm trying to create a class derived from both sf:: RenderTexture both sf:: Sprite, since there are methods with the same prototype in these two classes I avoid the ambiguities always calling methods with the complete "address" (eg sf :: RenderTexture: GetTexture() or sf:: Sprite:: GetTexture() instead of just GetTexture()). It seems to work just about everything, but I still get an error when I call sf:: RenderTexture:: Draw ().
here is the incriminated part of the code:
Code: [Select]
class myClass : public sf::RenderTexture, public sf::Sprite
{
   private :
       std::vector<sf::Drawable *> Obj;
        ...
   public :
        void myMethod()
        {
             ...
             sf::RenderTexture::Draw(*Obj[i]);
             ...
        }
        ...
};


It compile fine, but when i launch a program that uses this class i get the error
Quote
pure virtual method called

and i can't understand where the problem is. Can anyone help me to fix it?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
problem with sf::RenderTexture::Draw in derived class
« Reply #1 on: December 23, 2011, 10:38:24 am »
Quote
I'm trying to create a class derived from both sf:: RenderTexture both sf:: Sprite

It looks like a weird design decision. How can an object be seen by other objects as both a texture to render to, and a sprite to draw? One of these things, if not both, is most likely an implementation detail rather than a public part of the class' API.
Public inheritance is the strongest type of coupling in C++, it should be used wisely.

Quote
i can't understand where the problem is

How do you fill your Obj array? Can you show the code?
Laurent Gomila - SFML developer

carsaxy

  • Newbie
  • *
  • Posts: 11
    • View Profile
problem with sf::RenderTexture::Draw in derived class
« Reply #2 on: December 23, 2011, 11:43:54 am »
what I want is to create drawable objects that "contain" some other drawable so that when something is changed betwen them, automatically redraw all the "contained" object on it's textures. I had various test, but this idea seemed the best because it allowed me to import methods from both classes.

here is the complete code:
Code: [Select]
#include <SFML/Graphics/RenderTexture.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <vector>

#ifndef _OG_COMPDRW_HPP_
#define _OG_COMPDRW_HPP_

#ifndef _DESKTOP_SIZE_
#include <SFML/Window/VideoMode.hpp>
#define _DESKTOP_WIDTH_ sf::VideoMode::GetDesktopMode().Width
#define _DESKTOP_HEIGHT_ sf::VideoMode::GetDesktopMode().Height
#define _DESKTOP_SIZE_ sf::Vector2f(_DESKTOP_WIDTH_,_DESKTOP_HEIGHT_)
#endif

namespace og
{

class CompDrw : public sf::RenderTexture , public sf::Sprite
{
public :

CompDrw(){
sf::RenderTexture();
sf::Texture tmpTexture = sf::RenderTexture::GetTexture();
sf::Sprite::SetTexture(tmpTexture);
CompDrw::Show();
CompDrw::Updated = true;
CompDrw::Lightable = false;
}

CompDrw(bool isLghtble){
sf::RenderTexture();
sf::Texture tmpTexture = sf::RenderTexture::GetTexture();
sf::Sprite::SetTexture(tmpTexture);
CompDrw::Show();
CompDrw::Updated = true;
CompDrw::Lightable = isLghtble;
}

void Create(unsigned int width = _DESKTOP_WIDTH_, unsigned int height = _DESKTOP_HEIGHT_, bool depthBuffer = false) {
sf::RenderTexture::Create(width, height, depthBuffer);
CompDrw::Updated = false;
}

const bool IsLightable(){
return CompDrw::Lightable;
}

const bool IsOpen(){
return CompDrw::Shown;
}

void Show(bool showthis = true){
CompDrw::Shown = showthis;
}

void Hide(bool hidethis = true){
CompDrw::Show(!hidethis);
}

void Add(const sf::Drawable&){
CompDrw::myDrawableList.push_back(&object);
CompDrw::Updated = false;
}


void Swap(const sf::Drawable&, const sf::Drawable&){
int i1 = CompDrw::FindDrawable(obj1);
int i2 = CompDrw::FindDrawable(obj2);
if (i1==-1 || i2==-1) return;
std::swap( CompDrw::myDrawableList[i1], CompDrw::myDrawableList[i1] );
CompDrw::Updated = false;
}

void Cancel(const sf::Drawable&){
int i = CompDrw::FindDrawable(obj);
if (i==-1) return;
CompDrw::myDrawableList.erase( CompDrw::myDrawableList.begin() + i );
CompDrw::Updated = false;
}

void Empty(){
sf::RenderTexture::Clear();
CompDrw::myDrawableList.clear();
CompDrw::Updated = true;
}

void Clear(){
sf::RenderTexture::Clear();
CompDrw::Updated = false;
}

void Update(bool updating = true){
if (!updating)
{
CompDrw::Updated = false;
return;
}
if (CompDrw::Updated)
return;
CompDrw::UpdateTexture();
}


private :

void UpdateTexture(){
CompDrw::Clear();
int N = CompDrw::myDrawableList.size();
int i;
for ( i=0; i<N; i++ )
sf::RenderTarget::Draw(*CompDrw::myDrawableList[i]);
sf::RenderTexture::Display();
sf::Sprite::SetTexture(sf::RenderTexture::GetTexture(), true);
CompDrw::Updated = true;
}

int FindDrawable(const sf::Drawable&){
int N = CompDrw::myDrawableList.size();
int i;
for ( i=0; i<N; i++)
if ( CompDrw::myDrawableList[i] == &obj )
return i;
return -1;
}

bool Shown;
bool Lightable;

bool Updated;
std::vector<const sf::Drawable *> myDrawableList;

}; // end class CompostiteDrawable

} // end namespace og

#endif // end _OG_COMPDRW_HPP_
[/code]

carsaxy

  • Newbie
  • *
  • Posts: 11
    • View Profile
problem with sf::RenderTexture::Draw in derived class
« Reply #3 on: December 23, 2011, 11:46:16 am »
I did some debugging prints and i found that the program crashes when I call the sf::RenderTexture::Draw in the Update method

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
problem with sf::RenderTexture::Draw in derived class
« Reply #4 on: December 23, 2011, 11:59:16 am »
Quote
I had various test, but this idea seemed the best because it allowed me to import methods from both classes.

Importing functions is one thing that can be done with private inheritance. But making all of the imported functions available into the public API of the class has more important consequences, and is often not wanted. Do you really want one to be able to call SetTexture on your CompDrw objects? Won't it break the SetTexture that you do in your constructor, to link the RenderTexture and the Sprite together? That's just one example of something that should be kept as a private implementation detail, I guess there are many others.

Quote
CompDrw::myDrawableList.push_back(&object);

Be careful, you're taking the address of an object: it must remain alive as long as you use the stored pointer. In other words, don't do this:
Code: [Select]
CompDrw comp;
comp.Add(sf::Sprite(...));
// the sprite that you just stored the address of is already dead!

To avoid such problems, you can make things more explicit by taking a pointer argument in Add.
Laurent Gomila - SFML developer

carsaxy

  • Newbie
  • *
  • Posts: 11
    • View Profile
problem with sf::RenderTexture::Draw in derived class
« Reply #5 on: December 23, 2011, 01:14:34 pm »
Quote
the address of an object: it must remain alive as long as you use the stored pointer

ah, ok: it was precisely the problem of the program i made using this class.

Quote
you can make things more explicit by taking a pointer argument in Add

I like that idea, but there is a way to tell if the object pointed to still exist?

How can I import only some methods with private inheritance?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
problem with sf::RenderTexture::Draw in derived class
« Reply #6 on: December 23, 2011, 01:26:51 pm »
Quote from: "carsaxy"
I like that idea, but there is a way to tell if the object pointed to still exist?
The documentation. The pointer in the interface just prevents users from passing temporary objects.

Quote from: "carsaxy"
How can I import only some methods with private inheritance?
Not at all. If you want to do that, inheritance is the wrong approach. Use composition instead.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

carsaxy

  • Newbie
  • *
  • Posts: 11
    • View Profile
problem with sf::RenderTexture::Draw in derived class
« Reply #7 on: December 23, 2011, 01:30:16 pm »
Hmm... I am thinking that there arent many methods that I have to import from sf::RenderTexture, so I could put an object RenderTexture as a member and rewrite these methods...

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
problem with sf::RenderTexture::Draw in derived class
« Reply #8 on: December 23, 2011, 02:14:42 pm »
It's slightly easier with private inheritance, you can use the "using" keyword:
Code: [Select]
class MyClass : private sf::RenderTexture
{
public:
    using sf::RenderTexture::Create;
    ...
};
Laurent Gomila - SFML developer

carsaxy

  • Newbie
  • *
  • Posts: 11
    • View Profile
problem with sf::RenderTexture::Draw in derived class
« Reply #9 on: December 23, 2011, 03:12:41 pm »
Thank you very much!
I changed the inheritance from "public" to "private" and have premium methods that I was interested in using the directive "using" and everything seems to work  :D