How to get the set of sprites from bmp image C++ Texture - c++

I have this image:
I want to generate the set of sprites, each 32x32 in size. How can I do this with C++, no library used.
Texture class:
class Texture
{
protected:
// We cannot create or copy base class texture objects
// We will only ever have pointers or references to base
// class texture objects used in our program (and these
// will refer to derived class textures
Texture() = default;
Texture(Texture const &) = default;
Texture & operator=(Texture const &) = default;
virtual void LoadFromFile(std::string const & strFileName) = 0;
virtual void LoadFromResource(unsigned int rid) = 0;
public:
virtual ~Texture(){}
// virtual Rect const & GetBounds() const = 0;
virtual int Width() const = 0;
virtual int Height() const = 0;
};
using TEXTURE_PTR = std::shared_ptr<Texture>;
Sprite class:
class Sprite
{
private:
virtual void draw_impl(Canvas & c) = 0;
TEXTURE_PTR m_pTexture;
protected:
// Ensure that Sprite objects can only be constructed by derived classes
explicit Sprite(TEXTURE_PTR pt = nullptr,POINT2f const & p = { 0, 0 });
// All Sprite objects have a position state variable
POINT2f m_position;
// Sprite objects can only be copied by derived class objects
Sprite(const Sprite&) = default;
Sprite& operator=(const Sprite&) = default;
public:
virtual ~Sprite(){}
void OnDraw(Canvas & c);
void SetPosition(POINT2f const & pos);
POINT2f const & GetPosition() const;
void SetTexture(TEXTURE_PTR pt);
};
AND i create the sprite this way:
TEXTURE_PTR pLightning = std::make_shared<Texture>("resource//Lightning.bmp", RGB(255, 0, 255));
std::shared_ptr<Sprite> pSpark = std::make_shared<Sprite>(pLightning);
How can I generate 9 sprites from the above image with this method?
Edit
I come up with these code but still doesn't work
class WinTexture : public Texture
{
protected:
HBITMAP m_hbmImage;
HBITMAP m_hbmMask;
BITMAP m_bmParam;
virtual void LoadFromResource(UINT rid);
virtual void LoadFromFile(std::string const & strFileName);
void CreateMask(DWORD dwTransparent);
public:
// Construct from Windows Resource
WinTexture(UINT uid, COLORREF dwTransparent);
// Constructor from file load
WinTexture(std::string const & strFilename, COLORREF dwTransparent);
//Contruct from other Texture
WinTexture(std::shared_ptr<WinTexture> wt, int xStart,int yStart, int w, int h);
virtual ~WinTexture();
// Inherited interface
// virtual Rect const & GetBounds() const;
virtual int Width() const;
virtual int Height() const;
HBITMAP ImageHandle() const;
HBITMAP MaskHandle() const;
};
with this, I want to make a constructor to create from other WinTexture:
WinTexture::WinTexture(std::shared_ptr<WinTexture> wt, int xStart, int yStart, int w, int h)
: Texture(), // as above
m_hbmImage(NULL),
m_hbmMask(NULL) {
HDC hdcMem1 = CreateCompatibleDC(0);
HDC hdcMem2 = CreateCompatibleDC(0);
m_hbmImage = CreateBitmap(w, h, 1, 1, NULL);
//m_hbmImage = CreateCompatibleBitmap(hdcMem2, 1, 1);
SelectObject(hdcMem1, wt->ImageHandle());
SelectObject(hdcMem2, m_hbmImage);
BitBlt(hdcMem2, xStart, yStart, w, h,hdcMem1, 0, 0, SRCCOPY);
BitBlt(hdcMem1, xStart, yStart, w, h, hdcMem2, 0, 0, SRCINVERT);
//SaveDC(hdcMem2);
DeleteDC(hdcMem1);
DeleteDC(hdcMem2);
CreateMask(RGB(0, 0, 0));
}
EDIT
Currently, I have created this class from Sprite:
class TexturedSprite : public Sprite
{
private:
TEXTURE_PTR m_pTexture;
virtual void draw_impl(Canvas & c);
protected:
public:
explicit TexturedSprite(TEXTURE_PTR pt = nullptr, POINT2f pos = { 32, 32});
explicit TexturedSprite(int xStart,int yStart, int w, int h,TEXTURE_PTR pt = nullptr, POINT2f pos = { 32, 32 });
virtual ~TexturedSprite(){}
void SetTexture(TEXTURE_PTR pt);
};
I can't figure out how to implement the second constructor, to copy a part of input texture (pt):
TexturedSprite::TexturedSprite(int xStart, int yStart, int w, int h, TEXTURE_PTR pt , POINT2f pos )
:Sprite(pos)
{
HDC hdcMem1 = CreateCompatibleDC(0);
HDC hdcMem2 = CreateCompatibleDC(0);
//How to assign values to DC?
BitBlt(hdcMem1, 32, 32, w, h, hdcMem2, xStart, yStart, SRCCOPY);
DeleteDC(hdcMem1);
DeleteDC(hdcMem2);
}

At least as I read things right now, your basic intent is to load the texture, then create the individual sprites by copying 32x32 pixel pieces of the texture into the individual sprites. Unless you intend to manipulate the sprites from separate threads (which strikes me as unlikely) I'd avoid doing that.
Instead, I'd take note of a couple of the last parameters you supply to BitBlt:
BitBlt(hdcMem2, xStart, yStart, w, h,hdcMem1, 0, 0, SRCCOPY);
The 0, 0 just before the SRCCOPY specify the location in the source bitmap to use as the starting point of the BitBlt.
This lets you load the texture once, and just use that single texture for all the sprites it contains. Drawing an individual sprite at a particular location only requires that you specify the X, Y coordinates of that sprite within the source bitmap (specifically, the top, left-hand corner of that sprite) and draw a 32x32 chunk starting from there. If you want to define individual sprite objects, you can certainly do that, but each just needs to store something like a shared_ptr to the loaded texture, and the X, Y coordinates of its piece of the texture.
class Sprite {
shared_ptr<Texture> tex;
int x, y;
public:
Sprite(shared_ptr<Texture> t, int x, int y) tex(t), x(x), y(y) {}
void draw(HDC dc, int dest_x, int dest_y) {
BitBlt(dc, dest_x, dest_y, 32, 32, *tex, x, y, SRCCOPY);
}
};

If you really don't want to use any libraries you Need to manually decode the BMP file. Look at this Wikipedia entry for more Information about the structure of the BMP file Format.

Related

Call methods from classes from a vector of different classes

I'm using raylib to create some simple GUI elements, like Labels.
Each class has a void draw() method. For each widget, draw() needs to be called in the window mainloop. This leads to numerous draw() calls.
Instead of this, I'd like to define a DrawCalls class. This would have a std::vector containing each of the widget's draw().
Ideally widgets would be added like this
Drawcalls d;
Label foo("This is a Label", xLocation, yLocation, fontSize, font, colour);
d.addWidget(foo);
Then d.calls() would be called in the window's mainloop.
I've tried to pass the draw method as a function pointer and add it to a std::vector<void*> and then loop through the vector calling each void. Although this didn't work.
This is my code so far:
class Widget {
public:
void draw();
};
class DrawCalls {
private:
std::vector<Widget>
}
class Label : public Widget{
public:
Label(std::string text, float x, float y, float fontsize, Font font, Color colour = WHITE) {
this->text = text;
this->x = x;
this->y = y;
this->fontsize = fontsize;
this->font = font;
this->colour = colour;
}
void changeText(std::string newText) {
this->text = newText;
}
void setXY(float x, float y) {
this->x = x;
this->y = y;
}
void draw(bool draw) {
if (draw) {
DrawTextEx(this->font, this->text.c_str(), (Vector2){x,y}, this->fontsize, 0, this->colour);
}
}
protected:
std::string text;
float x, y;
float fontsize;
Font font;
Color colour;
};
class LabelWithBackground : protected Label {
public:
LabelWithBackground(std::string text, float x, float y, float fontsize, Font font, Color colour = WHITE, Color backgroundcolour = BLACK, Monopoly::padding padding = (Monopoly::padding){10, 10, 10, 10})
: Label(text, x, y, fontsize, font, colour) // Inherit from Label
{
this->backgroundcolour = backgroundcolour;
this->padding = padding;
Label::setXY((Label::x + padding.left), (Label::y + padding.top)); // Shift text over
}
void changeText(std::string newText) {
Label::changeText(newText);
}
void setXY(float x, float y) {
Label::setXY(x, y);
}
void draw(bool draw) {
if (draw) {
Vector2 measured = MeasureTextEx(Label::font, Label::text.c_str(), Label::fontsize, 0);
DrawRectangle(Label::x - this->padding.left, Label::y - this->padding.top, measured.x + this->padding.left + this->padding.right, measured.y + this->padding.top + this->padding.bottom, this->backgroundcolour);
Label::draw(true);
}
}
private:
Color backgroundcolour;
Monopoly::padding padding;
};
Thanks for any help pointing me in the right direction.

Custom font class crashes game

I'm using C++ with the SDL2 library to create a game. I'm using the SDL_ttf extension to be able to use ttf fonts and I'm trying to create my own class that would be more effective for multiple texts on the screen. The code I currently have starts out good, then crashes after about 15 seconds of running. I added more text and now it crashes after about 5 or 7 seconds. I'm looking for advice on how to solve this problem. my full Font class is as follows:
Font.h
#pragma once
#include "Graphics.h"
#include <string>
class Font
{
public:
Font(std::string path, SDL_Renderer* renderer);
~Font();
void FreeText();
void LoadText(int size, RGB_COLOR color, std::string text);
void Draw(int x, int y, Graphics& gfx, int size, RGB_COLOR color, std::string text);
private:
int width,height;
TTF_Font* font;
SDL_Texture* mTexture;
SDL_Renderer* renderer;
std::string path;
};
Font.cpp
#include "Font.h"
Font::Font(std::string path, SDL_Renderer* renderer)
:
font(NULL),
mTexture(NULL),
renderer(renderer),
path(path)
{
printf("Font con..\n");
}
Font::~Font()
{
}
void Font::LoadText(int size, RGB_COLOR color, std::string text)
{
font = TTF_OpenFont(path.c_str(), size);
SDL_Color c = {color.RED, color.GREEN, color.BLUE};
SDL_Surface* loadedSurface = TTF_RenderText_Solid(font, text.c_str(), c);
mTexture = SDL_CreateTextureFromSurface(renderer, loadedSurface);
width = loadedSurface->w;
height = loadedSurface->h;
SDL_FreeSurface(loadedSurface);
}
void Font::FreeText()
{
SDL_DestroyTexture(mTexture);
mTexture = NULL;
}
void Font::Draw(int x, int y, Graphics& gfx, int size, RGB_COLOR color, std::string text)
{
FreeText();
LoadText(size, color, text);
SDL_Rect rect = {x, y, width * gfx.GetGameDims().SCALE, height * gfx.GetGameDims().SCALE};
gfx.DrawTexture(mTexture, NULL, &rect);
}
My Graphics class just handles the actual drawing as well as dimensions of the game (screen size, tile size, color struct, gamestates, etc) So when I'm calling gfx.Draw it calls SDL_RenderCopy function.
Within my Game class I have a pointer to my Font class. (its called in my Game constructor) Then font->Draw() is called every frame; which destroys the original SDL_Texture, Loads the new text, then renders it on the screen.
My ultimate goal is to have my font class set up to where I choose the color and size from my draw function. Not sure what to check from this point on..
Any suggestions? Ideas?
This is what I get (which is what I want) but then it crashes.
I've managed to get it working. After searching a little more on SDL_ttf, I realized that in my FreeFont() function I was clearing out the SDL_Texture, however I did nothing with the TTF_Font.
Adding these lines in that function did the trick:
TTF_CloseFont(font);
font = NULL;

cpp private data member SDL_Rect inactive

I have a 7 x 7 matrix of probes that deliver a signal representing the level measured at that point in the area under investigation. I can draw a matric of 7 x 7 rectangles in SDL but I was unable to update the color.
I have a class
class Probe
{
public:
Probe();
~Probe();
void SetColor(int x);
void Set_id(int x, int y, int z);
void Level_id(void);
private:
int OldColor;
int Xcord;
int Ycord;
SDL_Rect rect; //This does not keep the rect that I create?
};
//outside all curly brackets {} I have
Probe Level[7][7];
//I initialize each instance of my class
Level[x][y].Set_id(x, y, z); and I use x and y to create and position the rectangle
// Defininlg rectangles
SDL_Rect rect = {BLOCK_W * Xcord, BLOCK_H * Ycord, BLOCK_W, BLOCK_H};
/*I get what I expected, by the way z sets the color and it is incremented so each rectangle has a different color. */
//I used function SetColor, it failed untill I regenerated rect
//in the SetColor function. I have
private:
SDL_Rect rect;
//It is private why do I need to re-create the SDL_Rect rect?
//Why is it not stored like
private:
int Xcord; // !!? Regards Ian.
If I understand correctly, your class looks something like this:
class Probe {
public:
Probe();
~Probe();
void SetColor(int x);
void Set_id(int x, int y, int z) {
SDL_Rect rect = {BLOCK_W * Xcord, BLOCK_H * Ycord, BLOCK_W, BLOCK_H};
}
private:
int OldColor;
int Xcord;
int Ycord;
SDL_Rect rect;
};
and you're wondering why the "rect" variable won't save as the private one, and how you change the color when drawing an SDL_Rect?
First of all, your "rect" isn't getting saved because you are defining a new "rect" variable in your function. What you should do is either of these:
rect = {BLOCK_W * Xcord, BLOCK_H * Ycord, BLOCK_W, BLOCK_H};
or
rect.x = BLOCK_W * Xcord;
rect.y = BLOCK_H * Ycord;
rect.w = BLOCK_W;
rect.h = BLOCK_H;
And to change the color of the rendering (assuming you are using the SDL_RenderDrawRect function, as that is the only one I know of that you can draw SDL_Rects with), you simply call:
SDL_SetRenderDrawColor(int r, int g, int b, int a);
right before you call the SDL_RenderDrawRect function (every time).
If you do not do this, and call the SetRenderDrawColor function somewhere else, your color will change to that color.

passing variable to multiple classes - C++

i'm new and still learning OOP and SDL for educational purpose.
so, i have a variable SDL_Renderer renderer. this variable needs to be initiated only once, and i initiate it in GameManager class.
and i have another class named Texture that needs that renderer.
this Texture will be used frequently.
so how do i pass this renderer? do i have to call GameManager in the Texture class? but if i do that, it means that i makeGameManager everytime i use the Texture right? or there is another way around?
thank you for helping me, i'm really sorry if my question is vague or not clear.
EDIT
this is Texture class
class Texture
{
public:
Texture();
~Texture();
int getWidth();
int getHeight();
bool loadFromFile(std::string path);
bool loadTextFromFile(std::string text, SDL_Color textColor, TTF_Font* font);
void render(int x, int y, SDL_Rect* clip = NULL);
void free();
bool lockTexture();
bool unlockTexture();
void* getPixels();
int getPitch();
private:
int vWidth;
int vHeight;
SDL_Texture* vTexture;
SDL_Renderer* renderer;
void* pPixels;
int pPitch;
};
this is the initiator
Texture::Texture()
{
vTexture = NULL;
vWidth = 0;
vHeight = 0;
renderer = GameManager::getRenderer();
}
this is GameManager class
class GameManager
{
public:
GameManager();
~GameManager();
bool intializeGame();
void gameLoop();
static SDL_Renderer* getRenderer();
private:
SDL_Window* window = NULL;
static SDL_Renderer* renderer;
TTF_Font* font = NULL;
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
};
the getRenderer() just a getter to pass the renderer
and this is my Main
int main(int argc, char* args[])
{
GameManager gameManager;
gameManager.intializeGame();
Texture charTexture;
SDL_Rect rect;
bool text = charTexture.loadFromFile("foo.png");
if (!text)
{
printf("texture not loaded");
}
rect.x = 0;
rect.y = 0;
rect.w = charTexture.getWidth();
rect.h = charTexture.getHeight();
while (true)
{
SDL_SetRenderDrawColor(GameManager::getRenderer(), 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(GameManager::getRenderer());
charTexture.render(10, 10, &rect);
SDL_RenderPresent(GameManager::getRenderer());
}
return 0;
}
i hope it's not confusing.
Disclaimer : I've never used SDL. This might be terrible, but it's based on what you gave me.
The important thing is the ownership. This is a shared ownership example. It's quite simple and takes the burden of figuring out when to destroy SDL_Renderer off of you.
class GameManager {
//BLABGLABLA
public:
std::shared_ptr<SDL_Renderer> getRenderer();
private:
std::shared_ptr<SDL_Renderer> renderer
}
class Texture
{
public:
Texture(std::shared_ptr<SDL_Renderer> theRenderer, //some other args)
private:
std::shared_ptr<SDL_Renderer> renderer;
}
So based on the name of the classes alone, you probably want GameManager to own the renderer, but you also want Texture to have access to it.
One way you can do that is to have a shared_ptr member in both classes, and to pass the renderer to texture in its constructor.
Basically the renderer object you initialized in GameManager, will only be destroyed when the last shared_ptr pointing to it is destroyed.

C++/Qt : change (the size of) a QImage that is being painted

I apologize if I give more details than necessary. I have a class Canvas that looks like this:
class Canvas : public QWidget
{
Q_OBJECT
public:
explicit Canvas(int width = 700, int height = 700, QWidget *parent = 0);
void setDelegate(CanvasDelegate *delegate);
private:
CanvasDelegate *delegate;
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *resizeEvent);
[...]
};
The Canvas::paintEvent(QPaintEvent *) function is implemented like this:
void Canvas::paintEvent(QPaintEvent *)
{
delegate->redrawBuffer();
QPainter canvas_painter(this);
canvas_painter.drawImage(0, 0, *(delegate->getImage()));
}
And so the class CanvasDelegate looks like this:
class CanvasDelegate
{
friend class Canvas;
public:
CanvasDelegate(const Canvas *canvas);
~CanvasDelegate();
const QImage * getImage() const;
void drawPoint(const Complex &z, const QColor &color = "black", int width = 3);
[...]
virtual void redrawBuffer(const H2Isometry &mobius = H2Isometry::identity()) = 0;
virtual void mousePress(QMouseEvent * mouseEvent) = 0;
[...]
protected:
const Canvas *canvas;
int sizeX, sizeY;
[...]
QPen *pen;
QImage *image;
QPainter *painter;
void rescale(int sizeX, int sizeY);
};
The constructor of CanvasDelegate is as follows:
CanvasDelegate::CanvasDelegate(const Canvas *canvas) : canvas(canvas)
{
pen = new QPen;
image = new QImage(canvas->width(), canvas->height(), QImage::Format_RGB32);
painter = new QPainter(image);
[...]
}
I'm not sure this is the best design ever but this is not my question (any comments are welcome, though). My problem is what happens when the window (Canvas) is resized. Here is what my code looks like:
void Canvas::resizeEvent(QResizeEvent *resizeEvent)
{
QSize newSize = resizeEvent->size();
delegate->rescale(newSize.width(), newSize.height());
//update();
}
void CanvasDelegate::rescale(int sizeX, int sizeY)
{
*image = QImage(sizeX, sizeY, QImage::Format_RGB32);
painter->eraseRect(0, 0, sizeX, sizeY);
this->sizeX = sizeX;
this->sizeY = sizeY;
[...]
}
The problem is that when I run the program, it crashes. Apparently there is a segmentation fault when painter->eraseRect(0, 0, sizeX, sizeY); is called in void CanvasDelegate::rescale(int sizeX, int sizeY). I don't understand why, I don't see what the problem is.
In a previous version, I had written the following (which now seems to me more complicated than necessary):
void CanvasDelegate::rescale(int sizeX, int sizeY)
{
QImage * oldImage = image;
QImage * newImage = new QImage(sizeX, sizeY, QImage::Format_RGB32);
QPainter * oldPainter = painter;
QPainter * newPainter = new QPainter(newImage);
newPainter->eraseRect(0, 0, sizeX, sizeY);
newPainter->setPen(*pen);
image = newImage;
painter = newPainter;
delete oldImage;
delete oldPainter;
this->sizeX = sizeX;
this->sizeY = sizeY;
[...]
}
But that does not work: I get a Qt error QPaintDevice: Cannot destroy paint device that is being painted. If I remove delete oldImage; and delete oldPainter;, everything works fine but that is a disgusting memory leak, isn't it.
Does someone understand why what I have written does not work, and what I need to do?
Thank you very much for your attention.
I'm not exactly sure why painter->eraseRect(0, 0, sizeX, sizeY); segfaults, but it may be that when the paintdevice of a QPainter is an image, its size shoudn't change, and therefore *image = QImage(sizeX, sizeY, QImage::Format_RGB32); breaks this assumption.
Therefore, I would try, before resizing the image, to delete the QPainter, then resize the image, then allocate a new QPainter. In code:
void CanvasDelegate::rescale(int sizeX, int sizeY)
{
delete painter;
*image = QImage(sizeX, sizeY, QImage::Format_RGB32);
painter = new QPainter(image);
painter->eraseRect(0, 0, sizeX, sizeY);
painter->setPen(*pen);
this->sizeX = sizeX;
this->sizeY = sizeY;
[...]
}