Store an array of SDL_Surface items in a class? - c++

I want to store all my SDL_Surface variables in an array, and to hold that array in a class. The reason is that I want to be able to reload all SDL_Surfaces based on events.
I think it should be something like this, I'm probably wrong though:
class Imgs_Arr{
private:
int pos;
public:
// DECLARE THE ARRAY
Imgs_Arr();
void addItem(char * path);
void changeItem(int pos);
};
Imgs_Arr::Imgs_Arr(){
// CREATE ARRAY
}
void Imgs_Arr::addItem(char * path){ // ADD ITEM IN LAST ARRAY POSITION
vec[pos] = load_image(path);
if( vec[pos] == NULL ) exit(5);
pos++;
}
void Imgs_Arr::changeItem(int p){ // ADD ITEM IN LAST ARRAY POSITION
vec[p] = load_image(path);
if( vec[p] == NULL ) exit(5);
}
I'm looking for an example of how to do it. But any information will be useful. Thanks

Your problem is somewhat specific, since SDL_Surface* is an opaque handle. You must never know the actual SDL_Surface object which it points to. So, you need a dynamic array of opaque handles. For the main array, we just use std::vector, so I'd do it like this:
#include <memory>
#include <vector>
#include <SDL.h>
class Arr_Images
{
using sdl_handle = std::unique_ptr<SDL_Surface, void(*)(SDL_Surface*)>;
sdl_handle wrap_unique_surface(SDL_Surface * s)
{
return sdl_handle(s, SDL_FreeSurface);
}
std::vector<sdl_handle> surfaces;
public:
void addImg(char const * path)
{
if (SDL_Surface * p = load_image(path))
{
surfaces.push_back(wrap_unique_surface(p));
}
else
{
// failed to load
}
}
};

Related

Custom Child Components Added But Not Visible

I am using the JUCE framework to create an audio plugin. I have created a Knob class which inherits from the Component class. My Knob class contains references to a Slider & a Label.
In my AudioProcessorEditor class, I initialize several Knob objects. However, none of the Components are visible at run-time. Am I doing something wrong or missing a step?
I have tried declaring Slider & Label objects directly inside of my AudioProcessorEditor class. When I do that, I am able to see the Slider & Label objects successfully at run-time. So I get the feeling that the issue involves my Knob class.
Knob.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
class Knob : public Component
{
public:
Knob(String, AudioProcessorEditor*);
~Knob();
void paint (Graphics&) override;
void resized() override;
String Name;
Label *KnobLabel;
Slider *KnobSlider;
AudioProcessorEditor *APE;
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Knob)
};
Knob.cpp
#include "Knob.h"
Knob::Knob(String name, AudioProcessorEditor *ape)
{
// In your constructor, you should add any child components, and
// initialise any special settings that your component needs.
this->Name = name;
APE = ape;
KnobLabel = new Label(name);
KnobLabel->setColour(0x1000281, Colours::antiquewhite);
KnobLabel->setAlwaysOnTop(true);
KnobLabel->setFont(10);
KnobSlider = new Slider();
KnobSlider->setAlwaysOnTop(true);
addAndMakeVisible(KnobLabel);
addAndMakeVisible(KnobSlider);
}
void Knob::paint (Graphics& g)
{
/* This demo code just fills the component's background and
draws some placeholder text to get you started.
You should replace everything in this method with your own
drawing code..
*/
g.setColour(Colours::white);
g.fillAll();
}
void Knob::resized()
{
// This method is where you should set the bounds of any child
// components that your component contains..
auto bounds = getLocalBounds();
KnobSlider->setBounds(bounds.removeFromTop(getHeight()*8));
KnobLabel->setBounds(bounds);
}
PluginEditor.h
#pragma once
#include "../JuceLibraryCode/JuceHeader.h"
#include "PluginProcessor.h"
#include "Knob.h"
#include "Model.h"
class MoonlightAudioProcessorEditor : public AudioProcessorEditor
{
public:
MoonlightAudioProcessorEditor (MoonlightAudioProcessor&);
~MoonlightAudioProcessorEditor();
void paint (Graphics&) override;
void resized() override;
Knob *OrbitKnob;
Knob *SpaceKnob;
Knob *InertiaKnob;
void ConfigureUI();
private:
OwnedArray<Knob> Knobs;
ComponentBoundsConstrainer ResizeBounds;
ResizableCornerComponent *Resizer;
MoonlightAudioProcessor& processor;
};
PluginEditor.cpp
#include "PluginProcessor.h"
#include "PluginEditor.h"
MoonlightAudioProcessorEditor::MoonlightAudioProcessorEditor (MoonlightAudioProcessor& p)
: AudioProcessorEditor (&p), processor (p)
{
setSize (400, 300);
ConfigureUI();
}
void MoonlightAudioProcessorEditor::ConfigureUI()
{
OrbitKnob = new Knob("Orbit", this);
SpaceKnob = new Knob("Space", this);
InertiaKnob = new Knob("Inertia", this);
Knobs.add(OrbitKnob);
Knobs.add(SpaceKnob);
Knobs.add(InertiaKnob);
for (Knob *knob : Knobs)
{
knob->KnobSlider->addListener(this);
addAndMakeVisible(knob);
knob->setAlwaysOnTop(true);
}
ResizeBounds.setSizeLimits(DEFAULT_WIDTH,
DEFAULT_HEIGHT,
MAX_WIDTH,
MAX_HEIGHT);
Resizer = new ResizableCornerComponent(this, &ResizeBounds);
addAndMakeVisible(Resizer);
setSize(processor._UIWidth, processor._UIHeight);
}
void MoonlightAudioProcessorEditor::paint (Graphics& g)
{
g.setColour (Colours::black);
g.fillAll();
}
void MoonlightAudioProcessorEditor::resized()
{
int width = getWidth();
int height = getHeight();
auto bounds = getLocalBounds();
auto graphicBounds = bounds.removeFromTop(height*.8);
auto orbitBounds = bounds.removeFromLeft(width/3);
auto spaceBounds = bounds.removeFromLeft(width/3);
if (OrbitKnob != nullptr)
{
OrbitKnob->setBounds(orbitBounds);
}
if (SpaceKnob != nullptr)
{
SpaceKnob->setBounds(spaceBounds);
}
if (InertiaKnob != nullptr)
{
InertiaKnob->setBounds(bounds);
}
if (Resizer != nullptr)
{
Resizer->setBounds(width - 16, height - 16, 16, 16);
}
processor._UIWidth = width;
processor._UIHeight = height;
}
Also, I have been using the AudioPluginHost application provided with JUCE to test my plugin. A lot of times the application will crash from a segmentation fault. Then I rebuild the plugin without changing anything and it will work.
I ended up figuring it out.
My components were being initialized after I set the size. A lot of the display logic was in the resize() function so I needed to set the size after component initialization.
You left out a call to Component::Paint(g) in Knob::Paint(Graphics& g)

Adding sprite to a node

I've got a SpritePlayer class, which holds my sprite.
SpritePlayer.h:
class SpritePlayer : public cocos2d::Node
{
public:
SpritePlayer();
CREATE_FUNC(SpritePlayer);
void InitSpritePlayer(std::string pathToSptire);
cocos2d::Sprite *GetSprite();
(...)
private:
cocos2d::Sprite *_sprite;
}
SpritePlayer.cpp:
void SpritePlayer::InitSpritePlayer(std::string pathToSprite)
{
_sprite = cocos2d::Sprite::create(pathToSprite);
}
cocos2d::Sprite *SpritePlayer::GetSprite()
{
return _sprite;
}
(...)
At MainScene.cpp I've got:
for (int i = 0; i < 4; i++)
{
playerSpritesList[i] = &SpritePlayer();
playerSpritesList[i]->InitSpritePlayer("ch2.png");
this->addChild(playerSpritesList[i]->GetSprite(), 0);
//SpritePlayersNode->addChild(playerSpritesList[i]->GetSprite())
}
And now the question - how could I add this sprite to a node?
Both bottom lines are causing errors, because I have to pass a Node into addChild() function.
The way you are going about it is introducing a level of abstraction that you do not need to have. The character itself can be a sprite, the way you have it your SpriteCharacter is not actually a sprite, it's a manager for a character sprite. I usually use the following pattern.
Character.h
class Character : public cocos2d::Sprite
{
public:
Character* createCharacterSprite(Vec2 position, std::string fileName);
private:
Character();
}
Character.cpp
Character* Character::createCharacterSprite(Vec2 position, std::string fileName)
{
auto character = new Character();
if(character && character->initWithFile(fileName))
{
character->autorelease();
return character;
}
}
MainScene.cpp
for (int i = 0; i < 4; i++)
{
auto character = Character::createCharacterSprite(characterPosition, "filename.png");
this->addChild(character);
}
This way you can manipulate from within CharacterSprite using 'this' instead of a pointer to your actual character sprite. Positioning and animations will also become a lot easier since you won't have another node with a possible different anchor point in between your character and your MainScene layer.
Sprite is a subclass of Node so there's not a problem with using addChild.
This line is suspicious:
playerSpritesList[i] = &SpritePlayer();
I'd remove SpritePlayer() constructor from your code, because CREATE_FUNC(SpritePlayer) creates default one, which manages memory. And then you can call playerSpritesList[i] = SpritePlayer::create();
Also you can write USING_NS_CC; in SpritePlayer (beware of Point struct - you have to write cocos2d::Point, because of namespace conflict on iOS/Mac).
Also for convention function names should start with lower case :)

how to remove variable sharing between objects?

Hi i am new to object oriented programming. here I intent to make three animation plots
subwindow_movie *child_Movie = new subwindow_movie;
child_Movie->setGeometry(20,100,620,560);
child_Movie->setplot(0);
child_Movie->show();
subwindow_movie *child_Movie1 = new subwindow_movie;
child_Movie1->setGeometry(680,100,620,560);
child_Movie1->setplot(1);
child_Movie1->show();
subwindow_movie *child_Movie2 = new subwindow_movie;
child_Movie2->setGeometry(325,350,620,560);
child_Movie2->setplot(2);
child_Movie2->show();
but the problem is that they all share same value of setplot i,e when the third subwindow_movie is created child_movie0 and child_movie1 both setplot values become 2; how to get rid of that... below is the set value function inside the class
#include "subwindow_movie.h"
#include "ui_subwindow_movie.h"
#include "plot.h"
#include <qapplication.h>
#include <qmainwindow.h>
int movie;
subwindow_movie::subwindow_movie(QWidget *parent) :
QDialog(parent),
ui(new Ui::subwindow_movie)
{
ui->setupUi(this);
}
subwindow_movie::~subwindow_movie()
{
delete ui;
}
void subwindow_movie::setplot(int value)
{
if (value ==0)
{ d_plot0 = new Plot( this );
movie=0;}
else if (value ==1)
{ d_plot1 = new Plot( this );
movie=1;}
else if (value ==2)
{ d_plot2 = new Plot( this );
movie=2;}
}
void subwindow_movie::on_movie_slider_valueChanged(int value)
{
if (movie ==0)
{ d_plot0->setAlpha(value);
}
else if (movie ==1)
{ d_plot1->setAlpha(value);
}
else if (movie ==2)
{ d_plot2->setAlpha(value);
}
}
the real problem is int movie which changes for with the creation of new child_movie causes the child_movie0 to run movie2. i dont want the movie variable changed for the child_movie0 with the creation of child_movie1.
With
int movie;
there is only one instance of the movie variable (it is a global variable). Each time you set its value, the previous value is overwritten.
Make movie a member variable instead:
class subwindow_movie {
int movie;
public:
...
}
Then, movie is available as separate instance for each subwindow_movie object you are creating. Inside the subwindow_movie methods, you can still access the variable as before.
Essentially, you should never use global variables - see also http://www.learncpp.com/cpp-tutorial/42-global-variables: Why global variables are evil

Change function that loads a font via loadFromFile() to loadFromMemory() in my resource class

I have this resource class that holds my resources (just fonts) for me. I call initialise() to load the resources, then I do
the normal program flow and before I exit the program I call cleanUp(). This is all working perfectly.
This is the code for the class. resources.h:
#ifndef __RESOURCES_H__
#define __RESOURCES_H__
#include <SFML\Graphics.hpp>
class Resources {
public:
Resources();
bool initialise();
void cleanUp();
bool loadAllFonts();
bool loadFont(std::string filename);
sf::Font &getFont(std::string filename);
const std::string myFont_;
const std::string myOtherFont_;
private:
const std::string fontPath_;
std::map<std::string, sf::Font*> fonts_;
};
#endif
resources.cpp:
#include "resources.h"
Resources::Resources() :
myFont_("./data/myFont.ttf"),
myOtherFont_("./data/myOtherFont.ttf")
{
}
bool Resources::initialise() {
if (loadAllFonts()) { return true; }
return false;
}
void Resources::cleanUp() {
std::map<std::string, sf::Font*>::iterator font_it;
for (font_it = fonts_.begin(); font_it != fonts_.end(); font_it++) {
delete font_it->second;
font_it->second = NULL;
}
fonts_.clear();
}
bool Resources::loadAllFonts() {
if (!loadFont(myFont_)) { return false; }
if (!loadFont(myOtherFont_)) { return false; }
return true;
}
bool Resources::loadFont(std::string filename) {
if (fonts_.find(filename) != fonts_.end()) {
return false;
}
sf::Font *font = new sf::Font();
sf::err().rdbuf(NULL);
if (!font->loadFromFile(filename)) {
delete font;
font = NULL;
return false;
}
const_cast<sf::Texture&>(font->getTexture(8)).setSmooth(false);
const_cast<sf::Texture&>(font->getTexture(12)).setSmooth(false);
const_cast<sf::Texture&>(font->getTexture(16)).setSmooth(false);
const_cast<sf::Texture&>(font->getTexture(24)).setSmooth(false);
fonts_.insert(std::pair<std::string, sf::Font*>(filename, font));
return true;
}
sf::Font &Resources::getFont(std::string filename) {
return *(fonts_.find(filename)->second);
}
This was simple enough and went without problems. I just use the class like this:
int main() {
//...
Resources resources_;
resources_.initialise();
sf::Text testText("test text", resources_.getFont(resources_.myFont_), 25);
// ... (program loop)
resources_.cleanUp();
return 0;
}
Now, what I want to do is the following:
In Resources::loadFont(), instead of loading a font from a file with loadFromFile(filename), I want to load it from memory.
I know how loading a font from memory works. I simply convert a font file and fill an unsigned char array with the font data:
unsigned char myFontChar[] = {0x00,0x01, .......... ,0x00,0x30,0x4f,0x53,0x2f};
Then I load the font like this:
sf::Font font;
if (!font.loadFromMemory(myFontChar, sizeof(myFontChar))) { return -1; }
This is working when I do it as demonstrated above, but I have no idea how I would go about adjusting the Resources::loadFont() function so that instead of loading the specified font from a file it loads it from memory (the unsigned char array).
Could you please help me and point me in the right direction?
I am not a pro, so this is hard for me, but I have some vague idea how to do it (in theory). I would apply the same principle that I currently have: Use an "identifier" so the std::map could be used.
Instead of std::map<std::string, sf::Font*> I would have to use something that replaces the second parameter sf::Font*, but I don't know what that would be and how the Resources::loadFont() function would then look like.
I hope I explained it well enough and really really hope someone can help me.
Thanks!
I'd not do this. It makes things less configurable and inflexible. Most users won't touch the directory a program resides in. On the flipside, if someone really, really wanted to change the font, they could still overwrite the portion of memory in your executable that contained the font. Assuming you do have a good reason for doing it, though, here's some ideas.
One way to do this is to simply initialize the std::map in your constructor, assigning whatever strings you want to your fonts:
bool Resources::loadAllFonts() {
sf::Font *tempfont;
tempfont = new sf::Font();
if (!(tempfont->loadFromMemory(myFontMem)) { return false; }
fonts_["myfont"] = tempfont;
tempfont = new sf::Font();
if (!(tempfont->loadFromMemory(myOtherFontMem)) { return false; }
fonts_["myotherfont"] = tempfont;
return true;
}
Later, you'll need to remember the strings you assigned.
However, the way I'd do it if you only have a few fonts is to store them in Resources as individual members and just convert the getFont() function into an if/else block:
#include <SFML\Graphics.hpp>
class Resources {
public:
//...
private:
const std::string fontPath_;
// Load these fonts in the constructor
sf::Font myFont;
sf::Font myOtherFont;
};
// ...
sf::Font &Resources::getFont(std::string fontname) {
if(fontname == "myfont") {
return myFont;
} else if(fontname == "myotherfont") {
return myOtherFont;
} else {
// Error somehow
}
}

how to display large data in wxListCtrl with using concept of wxThread

I'm capable to fill the database table in wxListCtrl,
my problem is to handle high range of data, I want to do this with the help of thread concept , perhaps it will save to hang the frame because of high amount of data.
I'm new in thread concept so your single lines will be a book for me.
Update:
My question was- how to display large data in wxListCtrl with using concept of wxThread
so for this I used thread concept I add two more files thread.c and thread.cpp
my entry thread code is shown below
void *MyThread :: Entry()
{
int i=1,j,k=0;
while(i!=400)
{
long index=this->temp->data_list_control->InsertItem(i,wxT("amit"));
for(j=1; j<3; j++) {
this->temp->data_list_control->SetItem(index,j,wxT("pathak"));
}
k++;
if(k==30) {
this->Sleep(1000);
k=0;
}
i++;
}
}
It is sometimes working fine but when I try to increase the value of i, it shows an error like
-*showingdatainwxlistctrl: ../../src/XlibInt.c:595: _XPrivSyncFunction: Assertion `dpy->synchandler == _XPrivSyncFunction' failed.*
or sometime it gives error like
***[Xcb] xcb_io.c:378: _XAllocID: Assertion `ret != inval_id' failed***
Why it is happening to me?
You can define your own thread object in wxWidgets in the following way:
class MyThread : public wxThread
{
private:
wxListCtrl* m_pListCtrl;
public:
MyThread(wxListCtrl* pListCtrl, wxThreadKind kind = wxTHREAD_DETACHED) :
wxThread(kind), m_pListCtrl(pListCtrl) {
}
virtual ~MyThread() {
}
virtual void* Entry() {
// here you have to place your code that will be running in separate thread
// m_pListCtrl-> ...
}
};
And this is the way how you can start your thread (assume you have your pListCtrl pointer here):
MyThread * pMyThread = new MyThread (pListCtrl);
wxThreadError ThreadError = pMyThread->Create();
if (wxTHREAD_NO_ERROR!=ThreadError) {
wxLogError(L"Can not create thread, wxThreadError '%d'", (int)ThreadError);
delete pMyThread;
return false;
}
ThreadError = pMyThread->Run();
if (wxTHREAD_NO_ERROR!=ThreadError) {
wxLogError(L"Can not run thread, wxThreadError '%d'", (int)ThreadError);
delete pMyThread;
return false;
}
// here, everything is ok.
Anyway, this is not the best solution for your problem. As far as I've understood, you need to display large amount of data in your wxListCtrl. To do this, you can use virtual ctrl (created with flag wxLC_VIRTUAL) and provide data source:
class MyListCtrl : public wxListCtrl
{
public:
MyListCtrl( ...) { ... }
virtual ~MyListCtrl();
protected:
virtual int OnGetItemImage(long item) const {
// You need this only if you want to provide specific image for your item.
// If you do not need it, just do not overload this method.
}
virtual wxString OnGetItemText(long item, long column) const {
// This is where you have to provide data for [item, column].
// Suppose, you have matrix A[n,m] which represents actually the data
// you want to display. The elements of this matrix can be of any type
// (strings, doubles, integers etc).
// You should return here wxString object that contains
// representation of the matrix's element A[item, column].
return ToWxString(A[item, column]);
// where ToWxString is your method that converts data to string
// So, you do not need to load all the data from A to wxListCtrl.
// Instead of it, wxListCtrl will determine which rows of the matrix should be
// displayed based on sizes and scroll position of wxListCtrl, and will
// call this method to obtain corresponding strings.
}
};
To create, you may use:
m_pListCtrl = new MyListCtrl( ..., ..., wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_VIRTUAL | wxSUNKEN_BORDER | wxLC_VRULES | wxLC_HRULES);
Best regards!
When you are performing high range of data you are bound to use WXThread in your program
Firstly was trying to fill wxListCtrl from wxEntry point, it was wrong u can not hit any main thread control from entry point, it does not give error, but it is a wrong concept
Here u need to pass the data to handler, handler will use it to fill wxListCtrl
code look like this->
void *MyThread :: Entry()
{
int a;
Handler handler_obj;
char *database_name=DATABASE_NAME;
connection =handler_obj.handler(101,database_name);
if(connection==NULL)
{
wxMessageBox(wxT("CAN NOT CONNECT TO DATABASE"), wxT("Message"), wxOK | wxICON_INFORMATION, NULL, -1, -1);
}
else
{
List_Ctrl_Data list_ctrl_data_object;
table_data=list_ctrl_data_object.fetch_table(connection);
MYSQL_ROW row;
while((row=mysql_fetch_row(table_data))!=NULL)
{
wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, 100000 );
void *row_data;
row_data=(void *)row;
event.SetClientData(row_data);
temp->GetEventHandler()->AddPendingEvent( event );
this->Sleep(1000);
}
}
}
to handle the row data we will use
void Id_Search_Report::onNumberUpdate(wxCommandEvent& evt)
{
int j;
void* hold_row;
hold_row=(void *)evt.GetClientData();
MYSQL_ROW row;
row=(MYSQL_ROW)hold_row;
const char* chars1 = row[0];
wxString mystring1(chars1, wxConvUTF8);
long index=data_list_control->InsertItem(this->counter,mystring1);
this->counter++;
for(j=1;j<12;j++)
{
const char* chars2=row[j];
wxString mystring2(chars2,wxConvUTF8);
data_list_control->SetItem(index,j,mystring2);
}
}
thread is returning a row , this method will handle the row and fill ListCtrl , it is a proper way to fill wxListCtrl.