Multiple definition errors in Arduino library - c++

I am trying to compile the lightRobot.ino Arduino sketch from https://github.com/janisHD/LightRobot in Arduino 1.0.5, but I'm getting multiple definition errors for the functions in the lightRobot library.
I'm using OS X 10.8.5 but had the same problem in Windows 8.
Here are example .h and .cpp files:
BlueToothEvent.h
/*! \file BlueToothEvent.h checks periodically if new data over BT has been received.
*/
#include <Arduino.h>
#include <OrangutanLCD.h>
#include "TimeEvent.h"
#ifndef BLUETOOTH_EVENT_H
#define BLUETOOTH_EVENT_H
#define DATA_WORD_LENGTH 4
/*! \class BlueToothEvent
retrieves and stores the received BT data. The data should come over the serialport, it must be started in "setup".
The struct DataPacket publishes the parsed data for the Statemanager.
*/
class BlueToothEvent : public TimeEvent
{
public:
struct DataPacket {
char speed;
char direction;
int color[4]; // [3]==blue [2]==green [1]==red [0]==brightness
int mode[2]; // [1]==color mode (0000->remote, 0001->blink, 0010->random, 0011->random&blink) [0]==drive mode (0000->remote, 0001->random)
};
BlueToothEvent();
~BlueToothEvent(){};
/*! Callback which is executed periodically*/
virtual void onTimeEvent();
/*! Returns an internal state.*/
virtual unsigned char getInternalState();
/*! Sets an internal state.*/
virtual void setInternalState(unsigned char state, bool update=false);
/*! Executes a more complex (and time consuming) action.*/
virtual void executeAction();
/*! To get the received data in the DataPacket struct
\return The most recent data received via Serial connection
*/
DataPacket getDataPacket();
bool m_new_data_present;
private:
/*! Processes the array with a 4 byte data word and saves the information in the DataPacket field.
\param data the array (must have the length of 4 bytes)
*/
void processData(unsigned char* data);
private:
enum Data{
velocity=0,//desired velocity
direction,//direction to drive
color,//desired color of the LEDs
mode,//the different modes: remote, random, blink
};
unsigned char m_data[DATA_WORD_LENGTH];
struct DataPacket m_data_packet;
};
#endif
BlueToothEvent.cpp
#include "BlueToothEvent.h"
BlueToothEvent::BlueToothEvent():
TimeEvent(),
m_new_data_present(false)
{
//init data array
m_data[velocity] = 0;
m_data[direction] = 0;
m_data[color] = 0;
m_data[mode] = 0;
processData(m_data);
//Serial connection
}
void BlueToothEvent::onTimeEvent()
{
//Code to receive a single data word and store it in m_data field
//Word consists of 4 chars (see the docu for further explanations):
//[0] -> direction to drive [0-254]
//[1] -> velocity to drive [0-254]
//[2] -> desired color for the Light [0-254] in 2 bit packets -> b0[0,3]->Brightnes | [0,3]->Red| [0,3]->Green | [0,3]->Blue
//[3] -> internal mode (see responsible class)[0-254]
if(Serial.available() >= DATA_WORD_LENGTH)
{//minimum number of bytes must be available in the buffer
while(Serial.available() > DATA_WORD_LENGTH)
Serial.read();//clear buffer except the last 4 bits
m_data[velocity] = (char)Serial.read();
m_data[direction] = (char)Serial.read();
m_data[color] = (char)Serial.read();
m_data[mode] = (char)Serial.read();
processData(m_data);
m_new_data_present = true;
}
}
void BlueToothEvent::processData(unsigned char* data)
{
m_data_packet.speed = data[velocity];
m_data_packet.direction = data[direction];
m_data_packet.color[0] = data[color] & 0b00000011;
m_data_packet.color[1] = (data[color] & 0b00001100)>>2;
m_data_packet.color[2] = (data[color] & 0b00110000)>>4;
m_data_packet.color[3] = (data[color] & 0b11000000)>>6;
m_data_packet.mode[0] = data[mode] & B00001111;
m_data_packet.mode[1] = (data[mode] & B11110000)>>4;
}
BlueToothEvent::DataPacket BlueToothEvent::getDataPacket()
{
m_new_data_present = false;
return m_data_packet;
}
//unsigned char BlueToothEvent::getData(unsigned char field)
//{
// if(field <= mode)
// return m_data[field];
// else
// return 0;
//}
unsigned char BlueToothEvent::getInternalState()
{
return m_data[mode];
}
void BlueToothEvent::setInternalState(unsigned char state, bool update)
{
//nothing to do here!
}
void BlueToothEvent::executeAction()
{
//nothing to do here!
}
I get the following errors on compilation - I've only shown the errors for the listed pair of .h/.cpp files - there are similar ones for every file in the lightRobot library:
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent::processData(unsigned char*)':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:43: multiple definition of `BlueToothEvent::processData(unsigned char*)'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:43: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:4: multiple definition of `BlueToothEvent::BlueToothEvent()'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:4: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:4: multiple definition of `BlueToothEvent::BlueToothEvent()'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:4: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent::getDataPacket()':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:56: multiple definition of `BlueToothEvent::getDataPacket()'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:56: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent::getInternalState()':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:73: multiple definition of `BlueToothEvent::getInternalState()'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:73: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent::setInternalState(unsigned char, bool)':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:78: multiple definition of `BlueToothEvent::setInternalState(unsigned char, bool)'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:78: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent::executeAction()':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:83: multiple definition of `BlueToothEvent::executeAction()'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:83: first defined here
lightRobot/BlueToothEvent.cpp.o: In function `BlueToothEvent::onTimeEvent()':
/Users/lemmy/Documents/Arduino/libraries/lightRobot/BlueToothEvent.cpp:18: multiple definition of `BlueToothEvent::onTimeEvent()'
BlueToothEvent.cpp.o:BlueToothEvent.cpp:18: first defined here
It seems that the errors are occurring in the object file, but I'm not sure why, as the header files have guards on them to prevent multiple definitions.

In case anyone else comes across this question later I was having the same problem and it was fixed by deleting the tabs on the library files in my sketch. It seems to include those files there and again when you have #include "lib.h"

The compilation succeeded when I moved the .ino file out of the lightRobot folder.

I know you already found the answer but, for future searchers, I had this same problem. I fixed it by renaming the main folder, for the .ino, and removing any .h or .cpp files from the folder.
Note: I don't know how this happened to me but it may be an issue for someone else.

Related

How to use RHVoice Text To Speech C/C++ library

I'm using rhvoice library in a qt c++ project, and I'm struggling to make it work and speak.
So far i have managed to load voices and voice profiles to a tts_engine, but no sound plays even tho the speak function gives no error.
So I'm wondering if someone could give me an example on how to initialize a tts engine and use it to speak strings, or any help on how to use this library, because the documentation wasn't enough for me to figure it out.
One thing i noticed is that RHVoice_callbacks causes my application to crash even if i just initialize it without using it.
Code:
The function that will implement the library:
short samples[]={140,139,145};
//initialize callbacks
/*RHVoice_callbacks *callbacks;
callbacks->set_sample_rate(24000,NULL);
callbacks->play_speech(samples,3,NULL);
callbacks->process_mark=NULL;
callbacks->word_starts=NULL;
callbacks->word_ends=NULL;
callbacks->sentence_starts=NULL;
callbacks->sentence_ends=NULL;
callbacks->play_audio=NULL;
callbacks->done=NULL;*/
RHVoice_init_params init_params;
char config[]="RHVoice.conf";
char one[]="RHVoice/languages/English/";
char two[]="RHVoice/voices/alan";
//initialize init_params
const char *array[] = {config,two,one,NULL};
init_params.resource_paths=array;
init_params.options=RHVoice_preload_voices;
//assisgn callbacks to init_params
/*init_params.callbacks.set_sample_rate(24000,NULL);
init_params.callbacks.play_speech(samples,3,NULL);
init_params.callbacks.process_mark=NULL;
init_params.callbacks.word_starts=NULL;
init_params.callbacks.word_ends=NULL;
init_params.callbacks.sentence_starts=NULL;
init_params.callbacks.sentence_ends=NULL;
init_params.callbacks.play_audio=NULL;
init_params.callbacks.done=NULL;*/
//initialize a tts_engine
RHVoice_tts_engine ttsengine=RHVoice_new_tts_engine(&init_params);
//debug
QVariant voiceprofnum = RHVoice_get_number_of_voice_profiles(ttsengine);
QVariant voiceprof = RHVoice_get_voices(ttsengine)->name;
QVariant voice = RHVoice_get_number_of_voices(ttsengine);
entrance->debug->setText(voiceprofnum.toString()+","+voiceprof.toString()+","+voice.toString());
//
//initialize synth_params without the voice profile because it causes a crash
RHVoice_synth_params synth;
synth.flags=0;
synth.capitals_mode=RHVoice_capitals_default;
synth.punctuation_mode=RHVoice_punctuation_default;
synth.relative_pitch=1;
synth.relative_volume=1;
synth.relative_rate=1;
synth.absolute_pitch=0;
synth.absolute_volume=1;
synth.absolute_rate=0;
//synth.voice_profile="Alan+Aleksandr";
//
//initialize RHVoice_message which will hold the string i want spoken
RHVoice_message userinput=RHVoice_new_message(ttsengine,"test",4,RHVoice_message_text,&synth,NULL);
RHVoice_speak(userinput);
RHVoice.h
#ifndef RHVOICE_H
#define RHVOICE_H
#include "RHVoice_common.h"
#ifdef __cplusplus
extern "C" {
#else
#include <stddef.h>
#endif
struct RHVoice_tts_engine_struct;
typedef struct RHVoice_tts_engine_struct* RHVoice_tts_engine;
typedef struct
{
/* These are the functions the caller is *required* to provide. */
/* This function will be called first. It will be called again if the sampling rate changes. Return 0 to signal an error. */
int (*set_sample_rate)(int sample_rate,void* user_data);
/* Return 0 to stop synthesis. */
int (*play_speech)(const short* samples,unsigned int count,void* user_data);
/* These functions are optional, */
/* but please make sure to set unused function pointers to 0. */
int (*process_mark)(const char* name,void* user_data);
int (*word_starts)(unsigned int position,unsigned int length,void* user_data);
int (*word_ends)(unsigned int position,unsigned int length,void* user_data);
int (*sentence_starts)(unsigned int position,unsigned int length,void* user_data);
int (*sentence_ends)(unsigned int position,unsigned int length,void* user_data);
int(*play_audio)(const char* src,void *user_data);
void (*done)(void* user_data);
} RHVoice_callbacks;
typedef enum {
RHVoice_preload_voices=1
} RHVoice_init_option;
typedef unsigned int RHVoice_init_options;
typedef struct
{
/* The paths should be encoded as utf-8 strings. */
const char *data_path,*config_path;
/* A list of paths to language and voice data. */
/* It should be used when it is not possible to collect all the data in one place. */
/* The last item in the array should be NULL. */
const char** resource_paths;
RHVoice_callbacks callbacks;
RHVoice_init_options options;
} RHVoice_init_params;
typedef enum {
RHVoice_message_text,
RHVoice_message_ssml,
RHVoice_message_characters,
RHVoice_message_key
} RHVoice_message_type;
struct RHVoice_message_struct;
typedef struct RHVoice_message_struct* RHVoice_message;
typedef struct
{
/* Language code. */
const char* language;
const char* name;
RHVoice_voice_gender gender;
/* Country code. */
const char* country;
} RHVoice_voice_info;
typedef struct
{
/* One of the predefined voice profiles or a custom one, e.g. */
/* Aleksandr+Alan. Voice names should be ordered according to their */
/* priority, but they must not speak the same language. If the */
/* combination includes more than one voice, automatic language */
/* switching may be used. The voice which speaks the primary language */
/* should be placed first. RHVoice will use one of the other voices */
/* from the list, if it detects the corresponding language. The */
/* detection algorithm is not very smart at the moment. It will not */
/* handle languages with common letters. For example, if you set this */
/* field to "CLB+Spomenka", it will always choose CLB for latin */
/* letters. Spomenka might still be used, if Esperanto is requested */
/* through SSML. */
const char* voice_profile;
/* The values must be between -1 and 1. */
/* They are normalized this way, because users can set different */
/* parameters for different voices in the configuration file. */
double absolute_rate,absolute_pitch,absolute_volume;
/* Relative values, in case someone needs them. */
/* If you don't, just set each of them to 1. */
double relative_rate,relative_pitch,relative_volume;
/* Set to RHVoice_punctuation_default to allow the synthesizer to decide */
RHVoice_punctuation_mode punctuation_mode;
/* Optional */
const char* punctuation_list;
/* This mode only applies to reading by characters. */
/* If your program doesn't support this setting, set to RHVoice_capitals_default. */
RHVoice_capitals_mode capitals_mode;
/* Set to 0 for defaults. */
int flags;
} RHVoice_synth_params;
const char* RHVoice_get_version();
RHVoice_tts_engine RHVoice_new_tts_engine(const RHVoice_init_params* init_params);
void RHVoice_delete_tts_engine(RHVoice_tts_engine tts_engine);
unsigned int RHVoice_get_number_of_voices(RHVoice_tts_engine tts_engine);
const RHVoice_voice_info* RHVoice_get_voices(RHVoice_tts_engine tts_engine);
unsigned int RHVoice_get_number_of_voice_profiles(RHVoice_tts_engine tts_engine);
char const * const * RHVoice_get_voice_profiles(RHVoice_tts_engine tts_engine);
int RHVoice_are_languages_compatible(RHVoice_tts_engine tts_engine,const char* language1,const char* language2);
/* Text should be a valid utf-8 string */
RHVoice_message RHVoice_new_message(RHVoice_tts_engine tts_engine,const char* text,unsigned int length,RHVoice_message_type message_type,const RHVoice_synth_params* synth_params,void* user_data);
/* On Windows the library is now built with MSVC instead of Mingw, */
/* so wchar_t will always mean utf-16 there */
RHVoice_message RHVoice_new_message_w(RHVoice_tts_engine tts_engine,const wchar_t* text,unsigned int length,RHVoice_message_type message_type,const RHVoice_synth_params* synth_params,void* user_data);
void RHVoice_delete_message(RHVoice_message message);
int RHVoice_speak(RHVoice_message message);
#ifdef __cplusplus
}
#endif
#endif
I tried setting the synth parameter in new_rhvoice_message function to null but it had no effect.
the voice profile attribute in synth parameters causes the application to crash as well.
Update:
I was told to use rhvoice via speech-dispatcher, and avoid using it directly.
I couldn't figure out how to do that, I have this package installed (rhvoice-speech-dispatcher-plugin.x86_64) on fedora. As far as i know, it doesn't provide any library that I can work with in my project, i can only use it from command line in a terminal.
I'm mentioning this in case it might help someone get closer to figuring this out.
Thank you for your time and help!

How to format data to be in type const uint16_t for use in an spi library

so I have been writing some code and finished it, all I had left to do was send it over SPI. However, I didn't realise that the SPI library I am using only accepts const uint_16t data. I tried setting up a temp variable of the correct data type and using a reference to send over SPI, which works, but because it is a const variable it cant change, which is something I need it to be able to do.
Below is my code, any help with this would be great, for reference this is done in C++ and uses SPI library is part of the Raspberry Pi Pico SDK (the code is cut down as is long so only needed parts included). I did try to use pointers to change the const variable which I think you can do in C but I couldn't get it to work in C++.
Any help with this would be greatly appreciated as I am very stuck as with how to go about fixing this.
Thanks,
Dean
class Frequency_Values{
Public:
static uint16_t position;
//constructors and special member functions here
private:
uint16_t MSB_LUT[401];
uint16_t LSB_LUT[401];
};
//----------static variable definition---------------------
unsigned short Frequency_Values::position = 0;
//---------------------------------------------------------
//-------------------get function definitions--------------
uint16_t Frequency_Values::get_MSB_LUT_Value()
{
return (Frequency_Values::MSB_LUT[position]);
}
uint16_t Frequency_Values::get_LSB_LUT_Value()
{
return (Frequency_Values::LSB_LUT[position]);
}
//-----------------------------------------------------------
Frequency_Values MSB, LSB;
int main(){
while(1){ // to show code runs multiple times
//--------------------------------------------------
const uint16_t LSB_Holder = LSB.get_LSB_LUT_Value(); // this is what I tried to get it in the correct data type
//which worked but as const the value wont change
const uint16_t MSB_Holder = MSB.get_MSB_LUT_Value();
//--------------------------------------------------
}
spi_write16_blocking(SPI_PORT, &LSB_Holder, 1);
spi_write16_blocking(SPI_PORT, &MSB_Holder, 1);
}
This was eventually fixed by just removing the const specifier inside of the pico sdk, spi library.

Storing value in 2d array variable during runtime in c++

My main code is .ino file for STM32F103C8T6 with STM32 official core. I have also included my library files of .h file and .cpp file.
I want store a values in 2d array called uint32_t Page[15][14]; in .h file of my library
How to store a value in 2d array variable during runtime. I have posted my code below. For me the code below is perfect, but still did not print the value stored in the array by calling the function HatriX_Signal with correct parameters. Kindly let me know what is wrong in my code below.
// .ino file
#include "HATRIX.h"
HATRIX Hatrix;
void setup()
{
Hatrix.HATRIX_INIT(115200);
}
void loop()
{
Hatrix.HatriX_Signal(Temperature_Signal, 0x66, Page[2][0]);
Serial.println(Page[2][0]);
Serial.println((float)Page[2][0] / 100);
}
// .h file
#ifndef HATRIX_H
#define HATRIX_H
#include "Arduino.h"
#include "Thermo_Couple_Input.h"
#define Number_of_Pages 15
#define Number_of_Bytes_Per_Page 64
static Thermo_Couple_Input TC_IN;
static uint32_t Page[Number_of_Pages][(Number_of_Bytes_Per_Page / 4) - 2];
enum Signal { Temperature_Signal,
Pressure_Signal,
Co2_Signal,
Analog_Industrial_Input_Signal,
General_Purpose_Output_Signal,
PWM_Power_Signal,
PWM_Voltage_Signal
};
class HATRIX
{
public:
void HATRIX_INIT(uint32_t bauderate);
void HatriX_Signal(uint8_t Signal, uint8_t I2C_Address, uint32_t Page);
};
#endif
// .cpp file
#include "HATRIX.h"
void HATRIX::HATRIX_INIT(uint32_t bauderate)
{
Serial.begin(bauderate);
}
// \brief Note: The value we get from Thermocouple is float value. So, we multiply the value with 100 and store it in specified static uint32_t Page by user.
// \param enum_Signal choose accordingly from enum signal: { Temperature_Signal ,
// Pressure_Signal ,
// Hatrix.Co2_Signal ,
// Analog_Industrial_Input_Signal ,
// General_Purpose_Output_Signal ,
// PWM_Power_Signal ,
// PWM_Voltage_Signal };
// \param I2C_Address Address of I2C to get the temperature from desired Thermocouple.
// \param Page Give the Page details to store your value. example: Hatrix.Page[4][3]
void HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address, uint32_t Page)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
Serial.println("Page");
Page = fThermocoupleTemperature * 100;
Serial.println(Page);
}
}
When calling HATRIX::HatriX_Signal(...), you pass a copy of a uint32_t of the multidimensional array Hatrix.Page to the function.
Inside the HATRIX::HatriX_Signal(...) function, you assign a new value to this variable called Page. But since it's just a copy of the value from the array, the array itself won't be effected by this.
In order to get the value of the function you can either use a pointer to the value in the array or a reference to the value in the array, preferably, return the value directly.
Your function could either look like this using a pointer:
void HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address, uint32_t* Page)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
TC_IN.fThermocoupleTemperature = TC_IN.fThermocoupleTemperature * 100;
Serial.println("Page");
*Page = TC_IN.fThermocoupleTemperature;
Serial.println(*Page);
}
}
and called like:
Hatrix.HatriX_Signal(Hatrix.Temperature_Signal, 0x66, &Hatrix.Page[2][0]);
or look like this using a reference:
void HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address, uint32_t& Page)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
TC_IN.fThermocoupleTemperature = TC_IN.fThermocoupleTemperature * 100;
Serial.println("Page");
Page = TC_IN.fThermocoupleTemperature;
Serial.println(Page);
}
}
and called like:
Hatrix.HatriX_Signal(Hatrix.Temperature_Signal, 0x66, Hatrix.Page[2][0]);
or alternatively, as I would advice, look like this:
uint32_t HATRIX::HatriX_Signal(uint8_t signal, uint8_t I2C_Address)
{
if(signal == Temperature_Signal);
{
TC_IN.Thermo_Couple_Input_Channel(I2C_Address);
TC_IN.fThermocoupleTemperature = TC_IN.fThermocoupleTemperature * 100;
Serial.println("Page");
uint32_t page = TC_IN.fThermocoupleTemperature;
Serial.println(page);
return page;
}
}
and called like:
Hatrix.Page[2][0] = Hatrix.HatriX_Signal(Hatrix.Temperature_Signal, 0x66);
How to fix this program:
Raw data such as this 2D array should be made private, as per the fundamental OO principle of private encapsulation.
Should you wish the user to access this array it should be done through a "setter" function taking (x,y) coordinates.
Provide a similar "getter" function for read/print access.
HatriX_Signal and similar should not pass along a pointer to data in a class member, because that's nonsense. You already have access to that data through the this pointer.
Generally, I'd advise to read a beginner-level book about C++ and OO, or alternatively ditch C++ completely if you have no intention of using OO program design anyhow.

Accessing members in a typedef map struct?

My question should be simple and I've spent that last few hours trying to get an answer to it by figuring it out on my own (and google-ing) answers and getting nowhere.
I've got the following in my header file:
Window.hpp
typedef struct {
SDL_Window* window = 0;
const char* title = 0;
int width;
int height;
int flags;
} m_windowStruct;
typedef std::map<std::string, m_windowStruct> m_windowMap;
m_windowMap windowMap; /* <-- Made this accessible */
and in my source file I've the following code:
Window.cpp
bool Window::createWindow(std::string id, const char* title, int width, int height, int flags) {
m_windowMap* windowMap;
m_windowStruct windowData;
windowData.window = SDL_CreateWindow("insert window creation info here");
if (!windowData.window) {
windowData.title = title;
windowData.width = width;
windowData.height = height;
windowData.flags = flags;
windowMap->insert(m_windowMap::value_type(id, &windowData));
SDL_LogInfo(INFO, "Window creation successful");
return true;
}
else {
return false;
}
};
Which works all fine and dandy... The problem I'm having is accessing the mapped struct members after.
For example if I want the instance of the primary window I'd want the following function:
/* Returns the window instance from the mapped struct */
SDL_Window* Window::getWindow(std::string id) {
m_windowMap::const_iterator keyValuePair = windowMap.find(id); /* <-- New error: Error: expression must have a class type */
if (keyValuePair == windowMap.end()) { /* <-- same error as just above */
return 0;
}
return keyValuePair->second.window; /* <-- Same error as just above */
};
I cannot for the life of me figure out how to access the second window member so that I can then give it to my renderer!
Any ideas?
I guess you want the windowMap being a global variable which is accessible across multiple source files (i.e., .cpp). Here are the changes you need to make,
In header file, replace the last line with extern m_windowMap* windowMap;. This makes variable accessible to all source files that include the header.
In your main function (or anywhere appropriate), add this line to initialize the map windowMap = new m_windowMap();
Remove m_windowMap* windowMap; in the Window::createWindow function, otherwise the re-declaration creates a new local m_windowMap and the rest of the function makes no effect to the global windowMap.
Lastly, since the global windowMap is a pointer, change .find() and .end() to ->find() and ->end() in the getWindow function.
If the windowMap is indeed a class member of Window, it is actually easier and cleaner.
From the code you originally posted, remove m_windowMap* windowMap; in the Window::createWindow function. Otherwise the insert goes to this newly created local map. Also, change ->insert to .insert as you did not declare windowMap as an pointer in the header.

Problem with reading data into structs using a C casting method

I'm writing an MD3 model loader in C++ and I understand the file format and what I need to do but I can't seem to get the syntax right. I have a class for the model and within that class there are a set of structs which will have the model data read into them. In the implementation of the class there is a constructor which reads data in when initialised with an MD3 file. I am using C style casting to do this. The first struct seems to be working and the data appears to be read in correctly but the following two seem to have all values left as zero which shouldn't be the case. The code compiles without error but I'm fairly new to C++ so I've probably made a simple mistake here!
The main file just set up the object with an MD3 file and then goes on to set up some OpenGL things but that's all working correctly and doesn't effect the constructor.
The interface:GameObject.h
class GameObject1 {
public:
GameObject1();
GameObject1(const char * filename);
virtual ~GameObject1();
virtual void Draw();
private:
struct md3_header_t
{
int IDENT; //id of file, always "IDP3"
int Version; //version number, always 15
char Name[64]; //name of character
int Flags; //blank but needed
int Num_frames; //number of Frames
int Num_surfaces; // number of shaders
int Num_skins; //...
int Num_triangles; //num triangles - important one
int Ofs_triangles; // offset of triangles
int Ofs_frames; // frames offset
int Ofs_tags; // tags offset
int Ofs_surfaces; //offset to surfaces
int Ofs_eof; //offset of end of header
};
typedef float vec3[3];
struct md3_frame_header_t
{
vec3 Min_bounds; //first corner of bounding box
vec3 Max_bounds; //other corner
vec3 local_origin; //usually 0 0 0
float Radius; //radius of bounding sphere
char NAME[16]; // name of frame
};
struct md3_tag_header_t
{
char NAME[64]; //name of tag
vec3 origin; //origin of tag eg head or torso
vec3 Axis[3]; //axis stuff
};
struct md3_surface_header_t
{
int IDENT; //id, must be IDP3
char Name[64]; //name of mesh
int Flags; // blank space
int Num_frames; // number of frames
int Num_shaders; // no shaders
int Num_vert; // number verts
int Num_triangles; //number of triangles
int Ofs_triangles; //offset of triangle data from surface start
int Ofs_shaders; // offset of shaders
int Ofs_st; // offset texture data
int Ofs_xyznormal; // offset of verts
int Ofs_end; // offset of end of surface section from start
};
and the interface GameObect.cpp, NOTE I've only included the constructor method here since the destructor and the draw method are both empty currently:
#include "GameObject1.h"
GameObject1::GameObject1() {
//if we have no model...
}
//constructor if a model has been provided
GameObject1::GameObject1(const char * filename) {
ifstream md3file;
md3file.open(filename, ios::in|ios::binary);
// C stuff
md3_header_t * md3header = (struct md3_header_t *)
malloc(sizeof(struct md3_header_t));
md3file.read((char *) md3header, sizeof (struct md3_header_t));
// Check the file
if (md3header->IDENT != 860898377) {
// Error!
cerr << "Error: bad version or identifier" << endl;
}
// seekg to search through the file to add new data to structs
// frame struct
md3_frame_header_t * md3frame = (struct md3_frame_header_t *)
malloc(sizeof(struct md3_frame_header_t));
md3file.seekg(md3header->Ofs_frames);
md3file.read((char *) md3frame, sizeof (struct md3_frame_header_t));
//surface struct
md3_surface_header_t * md3surface = (struct md3_surface_header_t *)
malloc(sizeof( md3_surface_header_t));
md3file.seekg(md3header->Ofs_surfaces);
md3file.read((char *) md3surface, sizeof (struct md3_surface_header_t));
md3file.close();
}
GameObject1::~GameObject1() {
// deconstructor
}
void GameObject1::Draw(){
// eventually a method to draw the model to screen using OpenGL and SDL
}
I'm really lost on this one so any help would be greatly appreciated.
Thanks,
Jon
Check the values of md3header->Ofs_frames and md3header->Ofs_surfaces to make sure they aren't trying to index past the end of the file. If they are, then the MD3 file may be corrupt or reading the file is not mapping properly to the struct.
Not sure if this is an issue but you may run into problems on 64 bit system if the the file was generated on a 32 bit (and vice versa) since the size of the ints would be different which would throw off the mapping to the struct.
May want to find a tool that you know can read the files properly and compare those values with the ones you are getting. Or use a hex editor to manually look through the file to verify the values.
Have a look at the memory layout of your structs: print out sizeof(float), sizeof(int), sizeof(char), sizeof(md3_frame_header_t), etc. and see if they are exactly what you expect. If not, you might want to play around with #pragma pack, to force the momory layout of your struct to be the file layout. Also, is the endianness of the bytes in the file the same as the in-memory layout?
In general I would also advise against reading structs from files. The few CPU cycles you save by doing this have mattered in the 90ies, but these day's they don't anymore. You should rather implement proper read and write code that reads and parses the fields as specified in the file format documentation, and then store them with set methods in your own in-memory representation. This makes the in-memory layout independent from the file layout, makes the code easier to debug, and easier to port if you want to switch to a different architecture or such
Your structures need to be aligned properly, look here.
Thanks for the help. I found the problem eventually by checking the size of the md3_header_t struct. There was an extra int in there (the Ofs_triangles) which shouldn't have been there. It's now reading the data perfectly so I'll get to work on the next part.
Thanks again,
Jon
My suggestion :
The code has memory leaks in constructor since you have not released memory allocated on heap .
so free the memory when its not of any use.
first you give exact values and then check
check size is properly or not