So I'm new to SFML. I read a lot of post, but I really don't get it.
I wrote an texture holder:
class tile_texture_holder {
private:
sf::Texture tx;
public:
tile_texture_holder(type a) {
switch (a) {
case type::desert:
tx.loadFromFile("C:/Users/Andreas/source/repos/conquer/Media/desert.png");
break;
case type::grass:
tx.loadFromFile("C:/Users/Andreas/source/repos/conquer/Media/grass.png");
break;
case type::mountain:
tx.loadFromFile("C:/Users/Andreas/source/repos/conquer/Media/mountain.png");
break;
case type::water:
tx.loadFromFile("C:/Users/Andreas/source/repos/conquer/Media/water.png");
break;
}
}
sf::Texture ret_texture() {
return tx;
}
~tile_texture_holder() {
std::cout << "///////////////////////HOLDER DELETED!!!/////////////////////" << std::endl;
}
};
And I tried to load a sprite with it in different ways....
For example:
tile_texture_holder t(type::desert);
sf::Sprite s;
s.setTexture(t.ret_texture());
(in the same function, where I draw the sprite)
I always get the white box being drawn. And I really dont get why the texture_holder is getting deleted.
BTW type is an enum.
I hope somebody can help me solve my issue!
s.setTexture(t.ret_texture());
in the line above you have undefined behaviour.
ret_texture returns temporary texture (it is returned by value, so a copy is made), setTexture takes reference to it, then at the end of expression temporary texture is destroyed and you have dangling reference in s.
Why this happens? Because setTexture of Sprite only holds reference to texture, it doesn't copy it.
According to SFML Sprite reference:
The texture argument refers to a texture that must exist as long as
the sprite uses it. Indeed, the sprite doesn't store its own copy of
the texture, but rather keeps a pointer to the one that you passed to
this function.
Solution: ret_texture should return texture by reference.
sf::Texture& ret_texture() {
return tx;
}
Related
I am trying to send the first element of an object to a function and modify its attributes and return back.
I have already created a Ray object with 20000 rays. Each single ray has its own properties.
How can I pass the first ray to a function to modify one of its property since I dont want to pass all rays because of computation time.
I tried to create a function that recevies a ray;
std::vector<Ray> hi(std::vector<Ray> bb)
{
bb.bounces++;
return bb;
}
and I tried to pass the first ray as:
hi(rays[0]);
but I receive 'no suitable used-defined conversion from "Ray" to "std::vector<Ray, std::allocator" exists.
Thank you for your help.
If you want to pass a single Ray, simply do so. If you want to modify it, pass it as reference (non-const), optionally returing reference to original:
Ray &hi(Ray &bb)
{
bb.bounces++; // modify the original, passed as reference
return bb; // return reference to original, for convenience
}
Or, if you don't want to modify original, but return a new, modified Ray, simply don't make it a reference:
Ray hi(Ray bb)
{
bb.bounces++; // argument is value, meaning copy, modify it
return bb; // return the copy
}
Or, another way to do the same, by passing const reference:
Ray hi(const Ray &bb)
{
auto result = bb; // get a copy
result.bounces++; // modify copy
return result; // return copy
}
If you use this option (either of above 2), you then need to modify the original by assignment:
rays[0] = hi(rays[0]);
I have a project where my textures are not displayed inside window properly. Instead of textures it will always show blank white sprites. I cant find out what I'am doing wrong. Here is my code:
class header with vector holding textures
class textures
{
public:
sf::Texture dirt_Texture;
sf::Texture grass_Texture;
std::vector<sf::Texture> texturesVector;
/*
dirt = 0
grass = 1
*/
public:
textures();
sf::Texture getTextureByID(int id);
};
and .cpp file for it:
//constructor populate vector with textures
textures::textures()
{
if (!dirt_Texture.loadFromFile("dirt.PNG"))
{
std::cout << "Error while loading texture.\n";
}
dirt_Texture.isSmooth();
texturesVector.push_back(dirt_Texture);
if (!grass_Texture.loadFromFile("grass.PNG"))
{
std::cout << "Error while loading texture.\n";
}
texturesVector.push_back(grass_Texture);
std::cout << "Texture constructor has been called.\n";
}
sf::Texture textures::getTextureByID(int id)
{
return texturesVector[id];
}
with child class sprite:
class sprites : public textures
{
private:
//textures* textureClass;
sf::Sprite sprite;
std::vector<int> textureIDsVector;
public:
sprites();
~sprites();
int getVectorValueAtLine(int &line);
void setVectorValueAtLineTo(int &line, int value);
void updateTextureAtLine(int& line);
sf::Sprite* getSprite();
};
where primary functions looks this in .cpp
sprites::sprites()
{
std::vector<int> cubeIDsVector(100, 0);
textureIDsVector = cubeIDsVector;
//textureClass = new textures();
std::cout << "Sprite constructor has been called.\n";
}
void sprites::updateTextureAtLine(int& line)
{
switch (textureIDsVector[line])
{
case 0:
//switcher = 0;
sprite.setTexture(getTextureByID(0));
sprite.setColor(sf::Color(55, 150, 150, 150));
std::cout << "case 0\n";
break;
case 1:
//switcher = 1;
sprite.setTexture(getTextureByID(1));
sprite.setColor(sf::Color(155, 50, 150, 150));
std::cout << "case 1\n";
break;
default:
break;
}
}
at main loop I create sprite object on the heap after sf::RenderWindow and after window.clean(...) call updateTextureAtLine() function from the for loop.
No error returned and at debug it seems fine too, I am new into it but it was looking like texture is always at memory, I cant find out where is the problem.
Solved as described below.
getTextureByID() returns a copy of a texture and not a reference. This copy is destroyed when it goes out of scope - so as soon as the call to sprite.setTexture() finishes.
This results in the Sprite having a pointer to a texture that no longer exists.
The solution is to instead return a pointer or a reference from getTextureByID(). Whilst we are changing that function we could should also make the function and returned value const as we are not planning on modifying it, although this is optional - it is a good habit I might as well point out.
Here is an example of a const function that returns a const reference:
// header
const sf::Texture& getTextureByID(int id) const;
// source
const sf::Texture& textures::getTextureByID(int id) const {
return texturesVector[id];
}
This should hopefully solve your problem.
Unrelated notes:
Your textures class is storing four textures total, two dirt textures, and two grass textures.
This might be what you intended, or this might not be.
One solution is to not have the member variables dirt_Texture and grass_Texture or just not to have texturesVector.
The other solution is to make texturesVector store pointers to textures, these could also be const and this would look like this:
// header
std::vector<const sf::Texture*> texturesVector;
// source
// constructor
texturesVector.push_back(&dirt_Texture);
...
texturesVector.push_back(&grass_Texture);
// getTextureByID()
return *texturesVector[id]; // (or alternatively return a pointer)
Finally, if you ARE storing texture objects inside of texturesVector (if you switch to pointers this won't be a problem), then note that adding any more textures might force the internal array of the vector to change memory location and thus invalidate your textures.
If you are not planning on adding more textures midway through running the program, then that is ok. I do add textures midway through running programs a lot because I like lazy initialization. If you are planning on adding more textures, then either use another container that does not move it's objects, or dynamically allocate a place for your textures. I am a fan of the latter, using a map of strings to unique pointers of textures (std::unordered_map<std::string, std::unique_ptr<sf::Texture>>)
Here is the following main function or my program
void scene_render(const struct Scene *s);
int main(void) { //leave main as is
struct Scene myScene;
scene_init(&myScene);
int keep_going = 1;
while (keep_going == 1) {
cons_clear_screen(); //clear off-screen display buffer
scene_render(&myScene); //render the scene to display buffer
cons_update(); //copy the display buffer to the display
cons_sleep_ms(ANIMATION_DELAY); //pause
scene_update(&myScene); //update the scene
int key = cons_get_keypress(); //see if the user has pressed a key
if (key != -1) {
keep_going = 0;
}
}
return 0;
}
void scene_render(Scene *s)
{
cons_clear_screen();
for(int i=0; i<NUM_PARTICLES; i++)
{
particle_render(&s->parts[i]);
}
}
When I run the makefile command on Cygwin, it passes the errors and starts compiling, but hits an error when it hits scene_render(&myScene);. It says that a reference to it is undefined. It refers to a variable in a function that is a const struct, while all other instances where &myScene is called are merely structs. Any idea what the issue may be? This lab is mostly about using pointers, if that helps.
The program (with assistance from external functions) should generate and throw randomly colored pixels around the command window, bouncing them back to keep them in the screen. Deleting the issue causes the program to compile successfully, but then loads a blank window that seems to do nothing.
Problem
With
void scene_render(const struct Scene *s);
you promise scene_render takes a const struct Scene as a parameter. By the way, you can discard the use of struct here. C++ knows Scene is a struct.
But the function that is defined is
void scene_render(Scene *s)
which takes a plain old, non-const Scene, so when the linker goes looking for a function that matches the promise it does not find one.
Solution
Change
void scene_render(Scene *s)
to
void scene_render(const Scene *s)
to keep the promise. But make certain that const-correctness is maintained throughout.
I have a class with a static variable. Since I need a constructor that isn't the default, I'm getting a little confused, but I hope I did it well
Class
class Object3D{
public:
static Object3D ObjControl;
Object3D(); //this is here just for the initialization of the static variable
Object3D(Triangle *mesh);
Triangle *mesh;
};
At this point I need to create an Object3D and I do as below
bool Engine::OnInit() {
if(SDL_Init(SDL_INIT_EVERYTHING) < 0) {
return false;
}
if((Surf_Display = SDL_SetVideoMode(WIDTH, HEIGTH, BBP, FLAGS)) == NULL) {
return false;
}
arma::colvec::fixed<3> upDirection;
upDirection << 0 << 1 << 0;
Camera cam(0.0, 0.0, 10.0, 10.0, 200.0, 90.0, upDirection);
Camera::CameraControl = cam;
arma::colvec::fixed<3> vertexA;
vertexA << -1 << 1 << 0;
arma::colvec::fixed<3> vertexB;
vertexB << 1 << 1 << 0;
arma::colvec::fixed<3> vertexC;
vertexC << 0 << -1 << 0;
Triangle tri(vertexA, vertexB, vertexC);
Triangle mesh[1];
mesh[0] = tri;
Object3D obj(mesh);
Object3D::ObjControl = obj; // PROBLEM! -> when the function extis from the OnInit ObjControl doesn't have anything inside.. it is like cleaned at the exit
return true;
}
The problem is the one that is inserted in the comment before the return.
Then when I need to pass that object to the rendering function, as below; the application closes because I'm trying to access to a location of memory not initialized
void Engine::OnRender(){
Rendering.WfRender(Object3D::ObjControl, Surf_Display, 1);
}
I think I'm doing something wrong with the static variable, but I did the same with a static variable for a Camera class, as you can see in the Engine::OnInit, and there everything works well. So I have no clue what's going on.
The main issue in your program is that you make a Triangle instance (mesh) in your function and that you pass a pointer to your static member variable ObjControl. When you leave the function, mesh is no longer available, so ObjControl points to an invalid instance. This could be solved by storing an actual Triangle instead of a pointer to a Triangle in Object3D or a container of Triangles if more are needed.
Does your Object3D class only hold onto the pointer to the mesh or take a copy of it?
Does it implement a deep-copy copy constructor?
I ask because your mesh is going out of scope after being assigned to obj, and obj is going out of scope after being assigned to the static variable. You need to either assign the mesh on the heap and hand that pointer to the static variable, or ensure the actual data is copied by correctly implementing the right constructors.
EDIT: Or, as this looks like games development, get it done quick and nasty! ;-)
Object3D::ObjControl.mesh = new Triangle(vertexA, vertexB, vertexC);
...and lose the local variables tri, mesh, and obj.
I apologize since this is rather a n00bish question, but I can't figure this one out.
class View //simplified
{
public:
ROILine* ROI() {return _roi;} //setter does some control stuff...
private:
ROILine *_roi;
}
class ROI : public eq::Object
{
public:
//virtual ROI(ROI* copy) = 0;
virtual ~ROI() {};
virtual uint32_t getType() = 0;
virtual void reset() = 0;
virtual bool addPoint( eq::Vector3f point ) = 0;
virtual bool previewPoint( eq::Vector3f point ) = 0;
virtual bool getNotationLocation( eq::Vector3f& point ) = 0;
virtual bool draw() = 0;
protected:
enum ROIType {
NONE = 0,
LINE,
POLY,
AREA,
VOLUME
};
enum ROIMeasure {
RM_LENGTH = 1,
RM_AREA,
RM_VOLUME,
};
private:
};
class ROILine : virtual public ROI
{
public:
ROILine();
ROILine(ROILine* copy);
ROILine(const ROILine& copy);
virtual ~ROILine() {SFLog(#"Destroying ROILine: 0x%x",this);};
void reset();
float distance() { return _start.distance(_end); }
// ROI Interface
uint32_t getType() { return ROI::LINE; }
virtual bool draw();
bool addPoint( eq::Vector3f point );
bool previewPoint( eq::Vector3f point );
bool getNotationLocation( eq::Vector3f& point );
eq::net::DataOStream& serialize(eq::net::DataOStream& os) ;
eq::net::DataIStream& deserialize(eq::net::DataIStream& is) ;
protected:
enum ROILineState { // RLS_
RLS_RESET,
RLS_START,
RLS_PREVIEW,
RLS_END,
};
private:
uint32_t _state;
eq::Vector3f _start;
eq::Vector3f _end;
};
ROILine::ROILine(const ROILine& copy) : ROI()
{
reset();
switch (copy._state)
{
case RLS_PREVIEW:
case RLS_END:
addPoint(eq::Vector3f(copy._start));
addPoint(eq::Vector3f(copy._end));
break;
case RLS_START:
addPoint(eq::Vector3f(copy._start));
break;
case RLS_RESET:
default:
break;
}
}
/*!
#abstract resets the line values and state
*/
void ROILine::reset()
{
_state = RLS_RESET;
_end = eq::Vector3f::ZERO;
_start = eq::Vector3f::ZERO;
}
/*!
#abstract if it has 2 points, draw the line. (_state > _PREVIEW)
#discussion assumes GL is already set up. Executes drawing commands.
#result true if the line was drawn
*/
bool ROILine::draw()
{
bool retVal = false;
if (_state >= RLS_PREVIEW) {
//glTranslatef(0.0f, 0.0f, -1.0f); //Back Up?
glColor3f( 1.0f, 0.0f, 0.0f ); //Red
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1 );
glBegin( GL_LINES );
{
glVertex3fv( _start.array );
glVertex3fv( _end.array );
}
glEnd();
//glTranslatef(0.0f, 0.0f, 1.0f); // Return
retVal = true;
}
return retVal;
}
// Elsewhere...
View *v = getView(); // returns the view object
// Destroys each time, but works wonderfully
ROILine r = ROILine(*(v->ROI()));
r.draw();
// Does not work (EXC_BAD_ACCESS)
v->ROI()->draw();
// Does not work (EXC_BAD_ACCESS on draw());
ROILine *r = v->ROI();
r->draw(); // debug shows r != 0x0
The Errors I get are as follows when I break on r->draw() and continue.
[Switching to process 12453]
Current language: auto; currently objective-c++
Warning: the current language does not match this frame.
(gdb) continue
Program received signal: “EXC_BAD_ACCESS”.
The "EXC_BAD_ACCESS" occurs on r->draw() or v->ROI()->draw() It doesn't step into the program at all, just halts and bt gives me a ??
My copy constructor works, because the draw() function actually draws where it's supposed to (instead of !!##$!4!## land) What I don't udnerstand, is why copying the value works, but accessing v->ROI()->draw() does not. it MUST have v->ROI() in order to make the copy!!
yes? ... no?
so confused...
Thanks,
Assuming that everything in your copy constructor for ROILine is working correctly, then here is a possibility: Something has overwritten a few bytes of the ROILine instance returned by View::ROI().
Most likely, the first several bytes of a ROILine object contain a pointer to the virtual function table for that class. (At least this is what typical C++ implementations do.) If those bytes get overwritten then instead of calling through the virtual function table, the program would end up calling through garbage and would almost certainly crash.
However, when making a copy of an object through a copy constructor, that pointer to the virtual function table is probably not accessed at all (unless you were to make a call to a virtual function in the copy constructor). In that case, all the data is copied successfully to a new object that has a correct vtable pointer.
Since draw is vritual, this would explain why calling it on the copy works while calling it on the original does not.
If this is what is happening, then you need to figure out what is overwriting part of your ROILine instance. If that instance is part of another object, then it may be easy. If that instance has been heap allocated individually, then it could be somewhat harder.
I think there's something strange going on.
You said code containing this line works wonderfully:
ROILine r = ROILine(*(v->ROI()));
In this line you perform *(v->ROI()) successfully.
But you said that if you try to do ROILine *r = v->ROI() then the value of r is NULL.
I don't think these can both be true (because that would mean you've successfully dereferenced a NULL pointer). I can think of two reasons for this:
Calling them sequentially does not work. If you move the "works wonderfully" block below the others, does it fail? If so, you may be copying a pointer and destroying it or the data it refers to. Then later, the data is not accessible.
The private ROILine* member of the View class is not set or initialized properly. Sometimes, this can lead to strange stochastic behavior; one compiled version (with the "works wonderfully block") may randomly initialize that member to be a nonzero value, while another compiled version (with one of the failing blocks) may randomly initialize that member to be zero. I've heard this referred to as a "Heisenbug" because trying to print out debugging information may change the problem.
Also, make sure you've verified that r is NULL after the line setting its value is executed. Some compilers initialize pointers to NULL and it may have not been set yet. Also check to make sure you have optimizations turned off; sometimes debuggers don't play well with optimizations, which can make a line of code execute after you think it's been executed.
The symptoms make it sound like your ROILine object has been deleted, leaving you with a dangling pointer to freed memory. When you try to call a virtual function, it crashes, because the vtable has been overwritten, but when you create a copy with the copy constructor it gets at least some valid data from the freed object, and appears to work.
I think ROILine should inherit from ROI.
Make draw virtual in ROILine and then
ROILine *r = v->ROI();
r->draw(); // debug shows r != 0x0
should work...
Connected to the problem (or not) It's a bad practice to call a function returning your ROI exactly like ROI constructor.
(referring to: ROILine* ROI() {return _roi;} //setter does some control stuff... )
Maybe the compiler gets confused...
Your copy constructor works as it takes a reference, and to do this you feed it a dereferenced (possibly null) pointer. This is one of those funny things in the language, as a reference to a dereferenced pointer doesn't actually dereference the pointer until you use the reference (C++ really is multi paradigm, it's even lazy!). Since this is undefined behavior, its only by chance that the copy constructor works at all. Its possible that in the View you've invalidated the pointer somehow.
#include <iostream>
using namespace std;
int addOne(int const & n) {
return n + 1; // Uh oh.
}
int main() {
int * ptr = 0;
cout << addOne(*ptr) << endl; // Doesn't crash here.
return 0;
}