I have a draw(SkCanvas* canvas) function.
In main() I write:
SkBitmap myBitmap;
myBitmap.allocN32Pixels(640, 480);
SkCanvas *myCanvas(&myBitmap);
draw(myCanvas);
But Visual Studio generates this error:
"a value of type "SkBitmap *" cannot be used to initialize an entity of type "SkCanvas*"
What am I doing wrong?
My draw() function clutters the post and is completely useless for this question otherwise I've posted it.
This is the construction for SkCanvas.
/** Construct a canvas with the specified bitmap to draw into.
#param bitmap Specifies a bitmap for the canvas to draw into. Its
structure are copied to the canvas.
*/
explicit SkCanvas(const SkBitmap& bitmap);
SkCanvas *myCanvas(&myBitmap);
this is a pointer to a canvas. The pointer types of SkCanvas* and SkBitmap* are unrelated.
SkCanvas myCanvas(&myBitmap);
this is a value of type myCanvas, initialized with a pointer to bitmap. If SkCanvas has a ctor taking a SkBitmap*, this should work.
It does not. It does have:
explicit SkCanvas(const SkBitmap& bitmap);
so this means:
SkCanvas myCanvas(myBitmap);
You'll probably also need to change the draw call to this:
draw(&myCanvas);
assuming that works. As a guess, you also need a refresher on the difference between pointers and values.
Related
I am using a library called "Pixel Game Engine", which has a Sprite and a Decal class. The documentation uses std::unique_ptr to create them, so I want to do the same to avoid any complications that may come later on.
Here is my code:
class Asset
{
private:
typedef std::unique_ptr<olc::Sprite> uniqueSprite;
typedef std::unique_ptr<olc::Decal> uniqueDecal;
private:
uniqueSprite LoadAssetImage(std::string fileName)
{
return std::make_unique<olc::Sprite>(fileName);
}
uniqueDecal MakeDecalFromSprite(uniqueSprite sprite)
{
return std::make_unique<olc::Decal>(sprite.get());
}
public:
uniqueSprite rockSprite = LoadAssetImage("rock.png"); //No Error here
uniqueDecal rockDecal = MakeDecalFromSprite(rockSprite); //Error here
};
Error:
function "std::unique_ptr<_Ty, _Dx>::unique_ptr(const std::unique_ptr<_Ty, _Dx> &) [with _Ty=olc::Sprite, _Dx=std::default_delete<olc::Sprite>]" cannot be referenced -- it is a deleted function
At first, I thought this is happening because the unique_ptr is being copied, but loading the sprite using LoadAssetImage() and assigning it to a variable works fine, so I am a little confused as to why this error is happening.
This is how the documentation loads them:
// Load Fragment Sprite
sprFragment = std::make_unique<olc::Sprite>("./gfx/tut_fragment.png");
// Create decal of fragment
decFragment = std::make_unique<olc::Decal>(sprFragment.get());
But I wanted to try something new :)
MakeDecalFromSprite passes a uniqueSprite by value, which involves making a copy. But std::unique_ptr has a deleted copy constructor so when you try to call MakeDecalFromSprite you get a compilation error.
The solution is to pass sprite by const reference instead:
uniqueDecal MakeDecalFromSprite(const uniqueSprite& sprite)
...
Then, you are not asking the compiler to make a copy.
This call:
uniqueSprite rockSprite = LoadAssetImage("rock.png");
works because of NVRO. This avoids the need to copy the function result. If this is not possible for any reason, the compiler can generate a move (std::unique_ptr is moveable).
I try to present text with the following code:
void Text::display(SDL_Renderer *renderer, int x, int y) {
// pos is an SDL_Rect and font is a TTF_Font
pos.x = pos.w = x;
pos.y = pos.h = y;
SDL_Surface *surface = TTF_RenderText_Solid(font, text.c_str(), color);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_QueryTexture(texture, NULL, NULL, &pos.w, &pos.h);
SDL_RenderCopy(renderer, texture, NULL, &pos);
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
}
In my Text class. At first I had an uninitialized SDL_Color color in my Text::display() method which let me present a text on the screen. (renderer is passed from main + coordinates x,y). But I decided to make my SDL_Color color a private variable in the class Text instead. And what is weird to me is that as a private variable the text was flickering once I presented it, but if I set it as a public variable or placed it in the method the text was not flickering. Or if I initialized it as a private variable (SDL_Color color = {255, 255, 255}).
My question is if there was only pure luck that it worked when color was uninitialized as a public or method variable or if they are treated differently? When I initialized color in the constructor it was also flickering if color was private.
My main method:
void fpsCap(Uint32 starting_tick) {
if ((1000 / fps) > SDL_GetTicks() - starting_tick) {
SDL_Delay(1000 / fps - (SDL_GetTicks() - starting_tick));
}
}
int main(int argv, char** args) {
// Create renderer, window, etc
while (true) {
SDL_RenderClear(renderer);
Text *txt = new Text("hello");
txt->display(gui->getRenderer(), 0, 0);
SDL_RenderPresent(renderer);
}
}
The value of the private member is not initialized, and so it gets random/garbage value. As you allocate new Text instance for every frame. You allocate on heap (every time in a new place), so it is sort of guaranteed to actually be garbage.
Why it didn't flicker in other cases?
Public member: my guess is that you also made it static? Static variables are zero-initialized (contrary to member variables).
Local variable: local variables are not zeroed and are considered to contain garbage, but as they are stack-allocated, they are likely to get identical piece of garbage every single time in the given place.
Private member assigned in the constructor: that is unexpected. Are you sure that it was the same constructor that is actually used? And that it was the same variable? Perhaps some name shadowing prevented the value from actually landing where our should?
Tangential:
You leak a Text instance every loop. You should delete every object created with new, or better, avoid using new altogether. Use unique_ptr/make_unique instead, or just local variables (much better in this case).
EDIT to answer questions about new:
In modern C++ you almost never need to use new.
If you have an object that is used only during the execution of the function, the natural thing to do is to keep it directly (i.e. not through a pointer), in this case defining the variable as
Text txt("hello");
This is a similar idiom to Java's Text txt = new Text("hello");, but the result variable is an instance itself, and not a reference to it.
If you want to create an instance that you immediately pass as an argument of type Text or const Text&, you can create it as temporary like SomeFunction(Text("hello")) (note the lack of new, it's just the class name).
If you need heap allocation, smart pointers (std::unique_ptr and std::shared_ptr) created with std::make_unique and std::make_shared are
strongly preferred, as they guard from many common pitfalls such as memory leaks and dangling pointers, at least as long as you keep hold of the smart pointer itself. std::shared_ptr is probably closest thing standard C++ has to Java reference, although it's not garbage collected, so if you make a cycle of them, they won't be ever freed.
You could replace your Text *txt = new Text("hello"); with
auto txt = std::make_unique<Text>("hello");
to get the same behavior, but with the Text getting destroyed and deallocated at the end of the block.
In my program I have a function that creates an outline of another sf::Text string which is as follows:
void textDisplay::createOutline(std::vector<textDisplay> &textDisplayVector, std::vector<textDisplay> &textDisplayVector2, textDisplay &textDisplay2)
{
//create text2 npc dialogue outline
textDisplay2.text.setString(textDisplayVector.back().text.getString());
textDisplay2.text.setPosition(textDisplayVector.back().text.getPosition().x + 1, textDisplayVector.back().text.getPosition().y + 1);
textDisplay2.text.setCharacterSize(textDisplayVector.back().text.getCharacterSize());
textDisplay2.text.setColor(sf::Color::Black);
//textDisplay2.text.setFont(textDisplayVector.back().text.getFont());
textDisplayVector2.push_back(textDisplay2);
}
I want to also copy the text's font, but i get this error:
'no suitable constructor exists to convert from "const sf::Font *" to "sf::Font"'.
I looked at the sfml documentation and I believe the issue lies with getFont() using a pointer rather than a reference. I have no idea how to implement this though. How can this commented out line of code that uses setFont() and getFont() be improved so that it works? All of the other lines of code work properly.
Like you suspect, the problem is that sf::Text::getFont returns a pointer to a Font, while sf::Text::setFont expects a reference to a Font as argument. Pointer != reference, therefore you get an error.
The solution is simple: Dereference (using the * operator) the pointer returned by getFont:
textDisplay2.text.setFont(*textDisplayVector.back().text.getFont());
// ^
// |
// Notice the dereference operator here
In my situation, the Drawing::Bitmap is created using a pointer to the pixel data. On the MSDN you can find a constructor doing exactly this:
Bitmap(int width, int height, int stride, PixelFormat format, IntPtr scan0);
From the documentation it is clear this constructor creates just the header and required things around the provided data. It is also noted, the caller have to release the pixel data array.
The caller is responsible for allocating and freeing the block of memory specified by the scan0 parameter. However, the memory should
not be released until the related Bitmap is released.
My problem is, if I pass a Bitmap with linked pixel data to another class, then I'm not able to release the underlying data. See my example bellow:
Drawing::Image^ FirstClass::GetImage(std::string ImagePath)
{
IplImage* cvImg = cvLoadImage(ImagePath.c_str());
Drawing::Image^ ManagedImg = gcnew Bitmap(
cvImg->width,
cvImg->height,
cvImg->widthStep,
Drawing::Imaging::PixelFormat::Format24bppRgb,
(System::IntPtr)cvImg->imageData);
return ManagedImg;
}
Void SecondClass::RefreshImage()
{
// Release the last image first
if (MyImage!=nullptr)
{
???
}
MyImage = GetImage(...);
}
A simple workaround is to pass, the IplImage* to the SecondClass, create the managed Bitmap there and then call cvReleaseImage(&Native_MyImage); there. However this works, I really want to know how to do it properly without passing IplImage*.
You need to pass pointers to pixels in some way.
For me, a better way would be to wrap IplImage* and ManagedImg into a single class that manages both of them. The destructor of the class would be responsible for destroying ManagedImg and then for calling cvReleaseImage() for stored value of the IplImage*. And then your GetImage function could return a pointer to this wrapper class, not to Drawing::Image.
I inserted bitmaps in CImageList in one Function and needed to change some of the images later in another function. But I am unable to extract the CBitmap. The code goes something like this:
CBitmap GetIndividualBitmap(CImageList oImgList, int nBmpNo)
{
IMAGEINFO imgInfo;
imagelist.GetImageInfo(index,imgInfo);
CBitmap bmp;
bmp.FromHandle(imgInfo.hbmImage);
return bmp;
}
However all I get is a black screen. Could anyone please point out where I am going wrong?
Ok there are a number of errors in your code
1)You are passing the Image list by object which means it will copy it across. Passing it by reference is a far better plan.
2) You are not passing a pointer to the IMAGEINFO struct into the GetImageInfo.
3) You misunderstand how "FromHandle" works. FromHandle is a static function that returns a pointer to a Bitmap. In your code you are calling the function and then ignoring the CBitmap* returned and returning a copy of your newly constructed object (ie it contains nothing) which results in your black screen.
Taking all those into account you should have code that looks like this:
CBitmap* GetIndividualBitmap(CImageList& oImgList, int nBmpNo)
{
IMAGEINFO imgInfo;
oImgList.GetImageInfo( nBmpNo, &imgInfo );
return CBitmap::FromHandle( imgInfo.hbmImage );
}