I wanted to be able to access my underlaying data structure when I pick a vtkActor. A class derived from vtkActor holding a ptr to my data structure seemed the easiest approach.
I get the subclass to compile just fine but the actor does not seem to be added to the renderer.
So, here's my class:
//.h
#include <vtkActor.h>
#include <vtkObjectFactory.h>
class Node;
struct Actor : public vtkActor {
static Actor* New();
vtkTypeMacro(Actor, vtkActor)
Node* holding_node;
};
//.cpp
#include "actor.h"
vtkStandardNewMacro(Actor)
In my rendering step: if I instantiate the actor with a vtkActor everything shows up as expected, picking works, etc...
vtkSmartPointer<vtkActor> sphereActor = vtkSmartPointer<vtkActor>::New();
But no actor is added if I use my Actor class
vtkSmartPointer<Actor> sphereActor = vtkSmartPointer<Actor>::New();
Nothing else changes in the code. Any ideas of what's wrong?
So, it turns out that there are a bunch of functions that need to be overloaded and a couple touches of macro magic to get this to work.
I pasted below the example that's working for me now. It is mostly from the vtkFollower code (a derived class from vtkActor). Hope this helps!
#include <vtkSmartPointer.h>
#include <vtkRenderer.h>
#include <vtkObjectFactory.h>
#include <vtkRenderingCoreModule.h>
#include <vtkProperty.h>
class Node;
class VTKRENDERINGCORE_EXPORT NodeActor : public vtkActor {
public:
vtkTypeMacro(NodeActor, vtkActor);
static NodeActor *New();
virtual void ReleaseGraphicsResources(vtkWindow *window) {
this->Device->ReleaseGraphicsResources(window);
this->Superclass::ReleaseGraphicsResources(window);
}
virtual int RenderOpaqueGeometry(vtkViewport *viewport){
if ( ! this->Mapper ) {
return 0;
}
if (!this->Property) {
this->GetProperty();
}
if (this->GetIsOpaque()) {
vtkRenderer *ren = static_cast<vtkRenderer *>(viewport);
this->Render(ren);
return 1;
}
return 0;
}
virtual int RenderTranslucentPolygonalGeometry(vtkViewport *viewport){
if ( ! this->Mapper ) {
return 0;
}
if (!this->Property) {
this->GetProperty();
}
if (!this->GetIsOpaque()) {
vtkRenderer *ren = static_cast<vtkRenderer *>(viewport);
this->Render(ren);
return 1;
}
return 0;
}
virtual void Render(vtkRenderer *ren){
this->Property->Render(this, ren);
this->Device->SetProperty (this->Property);
this->Property->Render(this, ren);
if (this->BackfaceProperty) {
this->BackfaceProperty->BackfaceRender(this, ren);
this->Device->SetBackfaceProperty(this->BackfaceProperty);
}
if (this->Texture) {
this->Texture->Render(ren);
}
this->ComputeMatrix();
this->Device->SetUserMatrix(this->Matrix);
this->Device->Render(ren,this->Mapper);
}
void ShallowCopy(vtkProp *prop) {
NodeActor *f = NodeActor::SafeDownCast(prop);
this->vtkActor::ShallowCopy(prop);
}
//****************************************//
// my member
//****************************************//
Node* node_i_represent{nullptr};
protected:
vtkActor* Device;
NodeActor() {
this -> Device = vtkActor::New();
}
~NodeActor() {
this -> Device -> Delete();
}
private:
};
vtkStandardNewMacro(NodeActor)
Related
I have an application with several Forms. Two of them are quite similar, they have features in the form of VCL objects (labels, images, etc...) in common, which I named the same.
I want to have a function in a specific class which can accept one of these two Form as a parameter in order to modify the parameters that they have in common. The solution I came around does not seem to work.
As my application is quite big and complicated, I replicated the problem using a small example.
First, below is an example of my MainForm :
And an example of one subForm (they are all arranged in a similar way)
I have an additionnal class which is used to fill in the Edits on the subForms. The code for this class is the following:
#pragma hdrstop
#include "master_class.h"
#include "sub_Form2.h"
#include "sub_Form3.h"
#include "sub_Form4.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
Master::Master(void)
{
}
Master::~Master(void)
{
}
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm = static_cast<TForm2*>(Form);
TForm3* self = dynamic_cast<TForm3*>(Form);
TForm2* self2 = dynamic_cast<TForm2*>(Form);
if (self != NULL && self2 == NULL) {
TForm3* curForm = static_cast<TForm3*>(Form);
}
else if (self == NULL && self2 != NULL) {
TForm2* curForm = static_cast<TForm2*>(Form);
}
curForm -> Edit1 -> Text = "blablabla_1";
curForm -> Edit2 -> Text = "blablabla_2";
}
And in the MainForm, the code for the "Fill Form2" button is the following:
Master1 -> WriteToForm(Form2);
where Master1 is just an object of the Master class.
This works very well for Form2 :
But for Form3, which is filled up using Master1 -> WriteToForm(Form3), here is what I get, which the same pb than in my real application:
So what should go to the Edit, is misplaced. I think the main pb comes from the fact that I did not create every label, edit, etc... on the same order. I did that on purpose to mimic my real application. To verify this, I created a 3rd subForm, where this time the VCL objects were created in the same order as my first subForm, and this works:
So I would suspect that this comes from the initial cast
TForm2* curForm = static_cast<TForm2*>(Form);
When I pass Form3 as an argument, Form3 is somewhat casted into the "shape" of Form2, which is not defined in the same order. Maybe this could be corrected by modifying directly the DFM file, but it is not a realistic approach for my main app.
I do this initial cast otherwise I get a compilation error saying that curForm is not known at the first line
curForm -> Edit1 -> Text = "blablabla_1";
So, is there a better way to pass the Form as an argument to the WriteToForm function?
Just because two types are similar does not mean they are related. Your code does not work because your two Form classes are not related to each other in any way. You can't just cast one to the other arbitrarily.
To solve this, you have several options:
code for both Form classes separately, eg:
void Master::WriteToForm(TForm* Form)
{
TForm2* curForm2 = dynamic_cast<TForm2*>(Form);
TForm3* curForm3 = dynamic_cast<TForm3*>(Form);
if (curForm2)
{
curForm2->Edit1->Text = _D("blablabla_1");
curForm2->Edit2->Text = _D("blablabla_2");
}
else if (curForm3)
{
curForm3->Edit1->Text = _D("blablabla_1");
curForm3->Edit2->Text = _D("blablabla_2");
}
}
Or:
void WriteToForm(TForm2* Form);
void WriteToForm(TForm3* Form);
...
void Master::WriteToForm(TForm2* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
void Master::WriteToForm(TForm3* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
Make your function use a template (however, be aware of this: Why can templates only be implemented in the header file?):
template<typename T>
void WriteToForm(T* Form);
...
void Master::WriteToForm<T>(T* Form)
{
Form->Edit1->Text = _D("blablabla_1");
Form->Edit2->Text = _D("blablabla_2");
}
make the two Form classes derive from a common base class or interface, eg:
class TBaseForm : public TForm
{
public:
inline __fastcall TBaseForm(TComponent *Owner) : TForm(Owner) {}
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TBaseForm
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TBaseForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(TBaseForm* Form)
{
Form->SetEdit1(_D("blablabla_1"));
Form->SetEdit2(_D("blablabla_2"));
}
Or:
__interface INTERFACE_UUID("{E900785E-0151-480F-A33A-1F1452A431D2}")
IMyIntf : public IInterface
{
public:
virtual void SetEdit1(const String &Text) = 0;
virtual void SetEdit2(const String &Text) = 0;
};
...
class TForm2 : public TForm, public IMyIntf
{
...
public:
__fastcall TForm2(TComponent *Owner);
...
void SetEdit1(const String &NewText);
void SetEdit2(const String &NewText);
};
__fastcall TForm2::TForm2(TComponent *Owner)
: TForm(Owner)
{
...
}
void TForm2::SetEdit1(const String &NewText)
{
Edit1->Text = NewText;
}
void TForm2::SetEdit2(const String &NewText)
{
Edit2->Text = NewText;
}
...
repeat for TForm3...
...
void Master::WriteToForm(IMyIntf* Intf)
{
Intf->SetEdit1(_D("blablabla_1"));
Intf->SetEdit2(_D("blablabla_2"));
}
use RTTI to access the fields, eg:
#include <System.Rtti.hpp>
void Master::WriteToForm(TForm* Form)
{
TRttiContext Ctx;
TRttiType *FormType = Ctx.GetType(Form->ClassType());
TRttiField *Field = FormType->GetField(_D("Edit1"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_1");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_1")));
}
}
Field = FormType->GetField(_D("Edit2"));
if (Field)
{
TValue value = Field->GetValue(Form);
if( (!value.Empty) && (value.IsObject()) )
{
TObject *Obj = value.AsObject();
// Either:
static_cast<TEdit*>(Obj)->Text = _D("blablabla_2");
// Or:
TRttiProperty *Prop = Ctx.GetType(Obj->ClassType())->GetProperty(_D("Text"));
if (Prop) Prop->SetValue(Obj, String(_D("blablabla_2")));
}
}
}
I need to create a custom blueprint node. I am using the blueprint function library.
The node will look like this:
Input:
int timedelayforeachloop
int numberofloops
output:
exc loop
exc completed
loop1.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "loop1.generated.h"
/**
*
*/
UENUM(BlueprintType)
enum class EMultiBranchEnum1 : uint8
{
BranchA,
BranchB
};
UCLASS()
class MYPROJECT2_API Uloop1 : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
UFUNCTION(BlueprintCallable, meta = (DisplayName = "loop", CompactNodeTitle = "2as2", ExpandEnumAsExecs = "Branches"), Category = "1")
//UFUNCTION(BlueprintCallable, Meta = (DisplayName = "Multi Branch1", ExpandEnumAsExecs = "Branches"), Category = 1)
static void multiBranch(EMultiBranchEnum1& Branches, int loopqty);
//EMultiBranchEnum1::BranchB;
};
loop1.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "loop1.h"
void Uloop1::multiBranch(EMultiBranchEnum1& Branches, int loopqty)
{
int currloop1 = 0;
int temp = 2;
int i;
for (i = 0; i < 10; i++){
currloop1 = currloop1 + 1;
Branches = EMultiBranchEnum1::BranchA;
}
if (temp > currloop1) {
Branches = EMultiBranchEnum1::BranchB;
}
if(temp == 0) {
Branches = EMultiBranchEnum1::BranchB;
}
}
-- THE PROBLEM --
The for loop only runs the once (evident by the print node i have on branchA(It only prints a single time))
-- What should happen with the code below --
the loop should run the 10 times (my print node should print 10 times)
Instead of using UBlueprintFunctionLibrary, you should use UBlueprintAsyncActionBase. It will allow you to store state in the node and call things connected to the execution pins asynchronously.
DelayLoop.h file:
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "DelayLoop.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDelayOutputPin);
/**
*
*/
UCLASS()
class TEST_API UDelayLoop : public UBlueprintAsyncActionBase
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(BlueprintAssignable)
FDelayOutputPin Loop;
UPROPERTY(BlueprintAssignable)
FDelayOutputPin Complete;
UFUNCTION(BlueprintCallable,
meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"),
Category = "Flow Control")
static UDelayLoop* DelayLoop(const UObject* WorldContextObject,
const float DelayInSeconds, const int Iterations);
virtual void Activate() override;
private:
const UObject* WorldContextObject;
float MyDelay;
int MyIterations;
bool Active;
UFUNCTION()
void ExecuteLoop();
UFUNCTION()
void ExecuteComplete();
};
DelayLoop.cpp file:
#include "DelayLoop.h"
#include "Engine/World.h"
#include "TimerManager.h"
UDelayLoop::UDelayLoop(const FObjectInitializer& ObjectInitializer) :
Super(ObjectInitializer), WorldContextObject(nullptr), MyDelay(0.0f),
MyIterations(0), Active(false)
{
}
UDelayLoop* UDelayLoop::DelayLoop(const UObject* WorldContextObject,
const float DelayInSeconds, const int Iterations)
{
UDelayLoop* Node = NewObject<UDelayLoop>();
Node->WorldContextObject = WorldContextObject;
Node->MyDelay = DelayInSeconds;
Node->MyIterations = Iterations;
return Node;
}
void UDelayLoop::Activate()
{
if (nullptr == WorldContextObject)
{
FFrame::KismetExecutionMessage(TEXT("Invalid WorldContextObject."),
ELogVerbosity::Error);
return;
}
if (Active)
{
FFrame::KismetExecutionMessage(TEXT("DelayLoop is already running."),
ELogVerbosity::Warning);
}
if (MyDelay <= 0.0f)
{
FFrame::KismetExecutionMessage(
TEXT("DelayLoop delay can't be less or equal to 0."),
ELogVerbosity::Warning);
}
if (MyIterations <= 0)
{
FFrame::KismetExecutionMessage(
TEXT("DelayLoop iterations can't be less or equal to 0."),
ELogVerbosity::Warning);
}
Active = true;
for (int i = 0; i <= MyIterations; i++)
{
FTimerHandle IterationTimer;
WorldContextObject->GetWorld()->GetTimerManager().SetTimer(
IterationTimer, this, &UDelayLoop::ExecuteLoop, MyDelay * i);
}
FTimerHandle CompleteTimer;
WorldContextObject->GetWorld()->GetTimerManager().SetTimer(
CompleteTimer, this, &UDelayLoop::ExecuteComplete,
MyDelay * (MyIterations+1));
// If the Complete pin should happen at the same time as the last iteration
// use `MyDelay * MyIterations` here instead
}
void UDelayLoop::ExecuteLoop()
{
Loop.Broadcast();
}
void UDelayLoop::ExecuteComplete()
{
Complete.Broadcast();
Active = false;
}
This will get you a blueprint that looks like this:
Note: This code is heavily based on This Creating Asynchronous Blueprint Nodes guide by Daniel ~b617 Janowski, now hosted in the legacy wiki here
I'm trying to get familiar with Graphics2D for NaCl, but I'm getting the error "NativeClient: NaCl module crashed" when I try to paint and flush my Graphics2D instance.
Here is the output of my calls to console.log:
View did change
Making graphics context
Drawing
Making blank image data
PaintAndFlush
Flush
I am on main thread
NativeClient: NaCl module crashed
Here is my index.html : https://jsfiddle.net/3c1y4wp9/
And here is my c++ code:
#include <deque>
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/cpp/var_array.h"
#include "ppapi/utility/completion_callback_factory.h"
namespace {
const uint32_t kBlue = 0xff4040ffu;
const uint32_t kBlack = 0xff000000u;
}
class GravitySimInstance : public pp::Instance {
public:
explicit GravitySimInstance(PP_Instance instance) : pp::Instance(instance)
{}
virtual ~GravitySimInstance() {}
private:
virtual void HandleMessage(const pp::Var& var_message) {
}
void PaintAndFlush(pp::ImageData* image_data) {
PostMessage("PaintAndFlush");
assert(!flushing_);
graphics_2d_context_.ReplaceContents(image_data);
PostMessage("Flush");
if (pp::Module::Get()->core()->IsMainThread()) {
PostMessage("I am on main thread");
} else {
PostMessage("I am NOT on main thread");
}
graphics_2d_context_.Flush(
callback_factory_.NewCallback(&GravitySimInstance::DidFlush));
flushing_ = true;
}
void DidFlush(int32_t error_code) {
PostMessage("DidFlush");
flushing_ = false;
}
virtual void DidChangeView(const pp::View& view) {
PostMessage("View did change");
if (size_ != view.GetRect().size()) {
size_ = view.GetRect().size();
const bool is_always_opaque = true;
PostMessage("Making graphics context");
graphics_2d_context_ = pp::Graphics2D(this, view.GetRect().size(),
is_always_opaque);
BindGraphics(graphics_2d_context_);
Draw();
}
}
void Draw() {
PostMessage("Drawing");
pp::ImageData image_data = MakeBlankImageData(size_);
PaintAndFlush(&image_data);
}
pp::ImageData MakeBlankImageData(const pp::Size& size) {
PostMessage("Making blank image data");
const bool init_to_zero = false;
pp::ImageData image_data = pp::ImageData(this,
PP_IMAGEDATAFORMAT_BGRA_PREMUL,
size,
init_to_zero);
uint32_t* image_buffer = static_cast<uint32_t*>(image_data.data());
for (int i = 0; i < size.GetArea(); ++i)
image_buffer[i] = kBlack;
return image_data;
}
pp::Graphics2D graphics_2d_context_;
pp::CompletionCallbackFactory<GravitySimInstance> callback_factory_;
/// The size of our rectangle in the DOM, as of the last time DidChangeView
/// was called.
pp::Size size_;
/// true iff we are flushing.
bool flushing_;
/// Stores the most recent histogram so that we can re-draw it if we get
/// resized.
double histogram_[10];
};
class GravitySimModule : public pp::Module {
public:
GravitySimModule() : pp::Module() {}
virtual ~GravitySimModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new GravitySimInstance(instance);
}
};
namespace pp {
Module* CreateModule() {
return new GravitySimModule();
}
} // namespace pp
Nothing looks obviously wrong, except where you initialize the image buffer. You need to take the stride into consideration when working with the image data. However, it doesn't look like you're writing out of bounds. Have you tried making init_to_zero true and using the ImageData as is to see if it still crashes?
Try calling of Flush function only in main thread. If you want to call such functions (which should be called in main thread) from working thread call them throuth pp::Core::CallOnMainThread function.
I'm trying to pass a single instance of my "Status" class to all my other classes so that they can all set and get the status.
I've been trying to do this by passing the "Status" class by reference into my "BaseStation" class. The code compiles fine but when I set the status from main and then get the status in "BaseStation" it has not changed.
I think this should be possible so I must be missing something.
Here is my main class
#include "mbed.h"
#include "Global.h"
#include "MODSERIAL.h"
#include "Status.h"
#include "Sensors.h"
#include "BaseStation.h"
#include "Rc.h"
#include "FlightController.h"
#include "NavigationController.h"
MODSERIAL _debug(USBTX, USBRX);
//Unused analog pins
DigitalOut _spare1(p16);
DigitalOut _spare2(p17);
DigitalOut _spare3(p18);
DigitalOut _spare4(p19);
//Classes
Status _status;
Sensors _sensors;
BaseStation _baseStation;
Rc _rc;
FlightController _flightController;
NavigationController _navigationController;
int main()
{
_debug.baud(115200);
DEBUG("\r\n");
DEBUG("********************************************************************************\r\n");
DEBUG("Starting Setup\r\n");
DEBUG("********************************************************************************\r\n");
//Set Status
_status.initialise();
//Initialise RC
//_rc.initialise(_status, p8);
//Initialise Sensors
//_sensors.initialise(p13, p14, p28, p27);
//Initialise Navigation
//_navigationController.initialise(_status, _sensors, _rc);
//Initialise Flight Controller
//_flightController.initialise(_status, _sensors, _navigationController, p21, p22, p23, p24);
//Initalise Base Station
_baseStation.initialise(_status, _rc, _sensors, _navigationController, _flightController, p9, p10);
DEBUG("********************************************************************************\r\n");
DEBUG("Finished Setup\r\n");
DEBUG("********************************************************************************\r\n");
_status.setState(Status::STANDBY);
int state = _status.getState();
printf("Main State %d\r\n", state);
}
Here is my Status.cpp
#include "Status.h"
Status::Status(){}
Status::~Status(){}
bool Status::initialise()
{
setState(PREFLIGHT);
DEBUG("Status initialised\r\n");
return true;
}
bool Status::setState(State state)
{
switch(state)
{
case PREFLIGHT:
setFlightMode(NOT_SET);
setBaseStationMode(STATUS);
setBatteryLevel(0);
setArmed(false);
setInitialised(false);
_state = PREFLIGHT;
DEBUG("State set to PREFLIGHT\r\n");
return true;
case STANDBY:
_state = STANDBY;
DEBUG("State set to STANDBY\r\n");
return true;
case GROUND_READY:
return true;
case MANUAL:
return true;
case STABILISED:
return true;
case AUTO:
return true;
case ABORT:
return true;
case EMG_LAND:
return true;
case EMG_OFF:
return true;
case GROUND_ERROR:
return true;
default:
return false;
}
}
Status::State Status::getState()
{
return _state;
}
bool Status::setFlightMode(FlightMode flightMode)
{
_flightMode = flightMode;
return true;
}
Status::FlightMode Status::getFlightMode()
{
return _flightMode;
}
bool Status::setBaseStationMode(BaseStationMode baseStationMode)
{
_baseStationMode = baseStationMode;
DEBUG("Base station mode set\r\n");
return true;
}
Status::BaseStationMode Status::getBaseStationMode()
{
return _baseStationMode;
}
bool Status::setBatteryLevel(float batteryLevel)
{
_batteryLevel = batteryLevel;
return true;
}
float Status::getBatteryLevel()
{
return _batteryLevel;
}
bool Status::setArmed(bool armed)
{
_armed = armed;
return true;
}
bool Status::getArmed()
{
return _armed;
}
bool Status::setInitialised(bool initialised)
{
_initialised = initialised;
return true;
}
bool Status::getInitialised()
{
return _initialised;
}
bool Status::setRcConnected(bool rcConnected)
{
_rcConnected = rcConnected;
return true;
}
bool Status::getRcConnected()
{
return _rcConnected;
}
Here is my status.h
#include "mbed.h"
#include "Global.h"
#ifndef Status_H
#define Status_H
class Status // begin declaration of the class
{
public: // begin public section
Status(); // constructor
~Status(); // destructor
enum State
{
PREFLIGHT,
STANDBY,
GROUND_READY,
MANUAL,
STABILISED,
AUTO,
ABORT,
EMG_LAND,
EMG_OFF,
GROUND_ERROR
};
enum FlightMode
{
RATE,
STAB,
NOT_SET
};
enum BaseStationMode
{
MOTOR_POWER,
PID_OUTPUTS,
IMU_OUTPUTS,
STATUS,
RC,
PID_TUNING,
GPS,
ZERO,
RATE_TUNING,
STAB_TUNING,
ALTITUDE,
VELOCITY
};
bool initialise();
bool setState(State state);
State getState();
bool setFlightMode(FlightMode flightMode);
FlightMode getFlightMode();
bool setBaseStationMode(BaseStationMode baseStationMode);
BaseStationMode getBaseStationMode();
bool setBatteryLevel(float batteryLevel);
float getBatteryLevel();
bool setArmed(bool armed);
bool getArmed();
bool setInitialised(bool initialised);
bool getInitialised();
bool setRcConnected(bool rcConnected);
bool getRcConnected();
private:
State _state;
FlightMode _flightMode;
BaseStationMode _baseStationMode;
float _batteryLevel;
bool _armed;
bool _initialised;
bool _rcConnected;
};
#endif
Here is my BaseStation.cpp
#include "BaseStation.h"
BaseStation::BaseStation() : _status(status){}
BaseStation::~BaseStation(){}
bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{
_status = status;
_rc = rc;
_sensors = sensors;
_navigationController = navigationController;
_flightController = flightController;
_wireless = new MODSERIAL(wirelessPinTx, wirelessPinRx);
_wireless->baud(57600);
_wirelessSerialRxPos = 0;
_thread = new Thread(&BaseStation::threadStarter, this, osPriorityHigh);
DEBUG("Base Station initialised\r\n");
return true;
}
void BaseStation::threadStarter(void const *p)
{
BaseStation *instance = (BaseStation*)p;
instance->threadWorker();
}
void BaseStation::threadWorker()
{
while(_status.getState() == Status::PREFLIGHT)
{
int state = _status.getState();
printf("State %d\r\n", state);
Thread::wait(100);
}
_status.setBaseStationMode(Status::RC);
}
Here is my BaseStation.h
#include "mbed.h"
#include "Global.h"
#include "rtos.h"
#include "MODSERIAL.h"
#include "Rc.h"
#include "Sensors.h"
#include "Status.h"
#include "NavigationController.h"
#include "FlightController.h"
#ifndef BaseStation_H
#define BaseStation_H
class BaseStation
{
public:
BaseStation();
~BaseStation();
struct Velocity
{
float accelX;
float accelY;
float accelZ;
float gps;
float gpsZ;
float barometerZ;
float lidarLiteZ;
float computedX;
float computedY;
float computedZ;
};
bool initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx);
private:
static void threadStarter(void const *p);
void threadWorker();
void checkCommand();
Thread* _thread;
MODSERIAL* _wireless;
Status& _status;
Status status;
Rc _rc;
Sensors _sensors;
NavigationController _navigationController;
FlightController _flightController;
char _wirelessSerialBuffer[255];
int _wirelessSerialRxPos;
};
#endif
The output when I run this is
********************************************************************************
Starting Setup
********************************************************************************
Base station mode set
State set to PREFLIGHT
Status initialised
Rc initialised
HMC5883L failed id check.IMU initialised
Sensors initialised
State 0
Base Station initialised
********************************************************************************
Finished Setup
********************************************************************************
State set to STANDBY
Main State 1
State 0
State 0
I think this is because I'm not in fact passing a single instance of "Status" but copying it.
How can I pass by reference properly?
Thanks
Joe
int x = 42;
int y = 9001;
int& r = x;
r = y;
Now x is 9001. You have not changed anything about r.
Similarly, in your code, although you accept a Status by reference, you then assign its value to a different object.
You may only initialise references. In your case you want to chain them.
Here's how you do what you want to do:
struct Status {};
struct T
{
T(Status& _ref) // 1. Accept parameter by reference;
: ref(_ref) // 2. Initialise member reference;
{} // now this->ref is a reference to whatever _ref was a reference to
Status& ref;
};
int main()
{
Status s;
T obj(s); // now obj holds a reference to s
}
You completely misunderstand how reference works in C++. You can set reference only in constructor and only in member initialization list, any other place you do assignment to object where that reference points to. So
BaseStation::BaseStation() : _status(status){}
Now your reference points to member status
bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{
_status = status;
Now you do assignment to object, where _status points to. So this code is actually equivalent to:
bool BaseStation::initialise(Status& status, Rc& rc, Sensors& sensors, NavigationController& navigationController, FlightController& flightController, PinName wirelessPinTx, PinName wirelessPinRx)
{
this->status = status;
It is not a good idea to replace constructor by initialize method in general, but in case you have reference, it is even worse. You need to either change it to a pointer, or initialize your objects properly - in constructor.
Cocos2d-x is a C++ port of Cocos2d-for-iPhone. It has the advantage of cross-platform. I'm using Cocos2d-x to develop games for Android and iPhone.
Right now I'm compiling a set of Cocos2d-X code with both Android NDK and Xcode.
On Xcode the game compiles and runs well on the iPhone.
With Android NDK, the compile would fail. (I'm using the official Android r7c NDK).
Please help.
Edited: For those of you who're interested in the full implementation file. Here it is.
#include "GameOverScene.h"
#include "HelloWorldScene.h"
using namespace cocos2d;
bool GameOverScene::init() {
if (CCScene::init()) {
this->_layer = GameOverLayer::node();
this->_layer->retain();
this->addChild(_layer);
return true;
} else {
return false;
}
}
GameOverScene::~GameOverScene () {
if (_layer) {
_layer->release();
_layer = NULL;
}
}
bool GameOverLayer::init () {
if (CCLayerColor::initWithColor(ccc4f(255, 255, 255, 255))) {
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
this->_label = CCLabelTTF::labelWithString("", "Artial", 32);
_label->retain();
_label->setColor(ccc3(0, 0, 0));
_label->setPosition(ccp(winSize.width/2, winSize.height/2));
this->addChild(_label);
this->runAction(CCSequence::actions(CCDelayTime::actionWithDuration(3), CCCallFunc::actionWithTarget(this, callfunc_selector(GameOverLayer::gameOverDone)), NULL));
return true;
} else {
return false;
}
}
void GameOverLayer::gameOverDone() {
CCDirector::sharedDirector()->replaceScene(HelloWorld::scene());
}
GameOverLayer::~GameOverLayer() {
if (_label) {
_label->release();
_label = NULL;
}
}
And the full header file
#ifndef S6_GameOverScene_h
#define S6_GameOverScene_h
#include "cocos2d.h"
class GameOverLayer : public cocos2d::CCLayerColor {
public:
GameOverLayer():_label(NULL) {};
virtual ~GameOverLayer();
bool init();
LAYER_NODE_FUNC(GameOverLayer);
void gameOverDone();
CC_SYNTHESIZE_READONLY(cocos2d::CCLabelTTF*, _label, Label);
};
class GameOverScene : public cocos2d::CCScene {
public:
GameOverScene():_layer(NULL) {};
~GameOverScene();
bool init();
//SCENE_NODE_FUNC(GameOverScene);
static GameOverScene* node()
{
GameOverScene *pRet = new GameOverScene();
//Error: undefined reference to `GameOverScene::init()'
if (pRet && pRet->init())
{
pRet->autorelease();
return pRet;
}
else
{
//Error: undefined reference to `vtable for GameOverScene'
delete pRet;
pRet = NULL;
return NULL;
}
};
CC_SYNTHESIZE_READONLY(GameOverLayer*, _layer, Layer);
};
#endif
It might be problem with Android.mk file.. In that you need to add your GameOverScene.h file for compilation..
/Users/my_account_name/Desktop/Projects/S6/S6/android/jni/../../Classes/GameOverScene.h:40: undefined reference to GameOverScene::init()'
You have to link with GameOverScene's object file.
You might forget to add GameOverScene.cpp in Android.mk located at Classed folder.