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.
Related
I'm currently trying for a game project to get rid of a dangling reference when a plane crashes before reaching the terminal it was booked to reach.
I would like to go through <algorithm> functions only to better understand how they work.
At the moment I've tried going through the map that contains all the planes associated with a terminal, comparing it with the list of all the planes and checking if a plane that is in the map is no longer in the vector then delete it from the map to free the associated terminal.
void remove_crashed_aircraft(std::unordered_map<const Aircraft*, size_t>& reserved_terminals, std::vector<std::unique_ptr<Aircraft>>& aircrafts)
{
auto it = std::all_of(reserved_terminals.begin(), reserved_terminals.end(),
[aircrafts](const Aircraft* a1){ return std::find_if(aircrafts.begin(), aircrafts.end(),
[a1](std::unique_ptr<Aircraft> a2){ return a1==a2.get();});});
reserved_terminals.erase(it);
}
And this is my Aircraft class:
class Aircraft : public GL::Displayable, public GL::DynamicObject
{
private:
const AircraftType& type;
const std::string flight_number;
Point3D pos, speed; // note: the speed should always be normalized to length 'speed'
WaypointQueue waypoints = {};
Tower& control;
bool landing_gear_deployed = false; // is the landing gear deployed?
bool is_at_terminal = false;
int fuel = 0;
// turn the aircraft to arrive at the next waypoint
// try to facilitate reaching the waypoint after the next by facing the
// right way to this end, we try to face the point Z on the line spanned by
// the next two waypoints such that Z's distance to the next waypoint is
// half our distance so: |w1 - pos| = d and [w1 - w2].normalize() = W and Z
// = w1 + W*d/2
void turn_to_waypoint();
void turn(Point3D direction);
// select the correct tile in the plane texture (series of 8 sprites facing
// [North, NW, W, SW, S, SE, E, NE])
unsigned int get_speed_octant() const;
// when we arrive at a terminal, signal the tower
void arrive_at_terminal();
// deploy and retract landing gear depending on next waypoints
void operate_landing_gear();
void add_waypoint(const Waypoint& wp, const bool front);
bool is_on_ground() const { return pos.z() < DISTANCE_THRESHOLD; }
float max_speed() const { return is_on_ground() ? type.max_ground_speed : type.max_air_speed; }
bool is_paused = false;
Aircraft(const Aircraft&) = delete;
Aircraft& operator=(const Aircraft&) = delete;
public:
Aircraft(const AircraftType& type_, const std::string_view& flight_number_, const Point3D& pos_,
const Point3D& speed_, Tower& control_, int fuel_) :
GL::Displayable { pos_.x() + pos_.y() },
type { type_ },
flight_number { flight_number_ },
pos { pos_ },
speed { speed_ },
control { control_ },
fuel { fuel_ }
{
speed.cap_length(max_speed());
}
const std::string& get_flight_num() const { return flight_number; }
float distance_to(const Point3D& p) const { return pos.distance_to(p); }
bool is_circling() const
{
if (!has_terminal() && !is_at_terminal)
{
return true;
}
return false;
}
bool has_terminal() const
{
if (waypoints.empty())
{
return false;
}
else
{
return waypoints.back().type == wp_terminal;
}
}
bool is_low_on_fuel() const
{
if (fuel<200)
{
return true;
}
else
{
return false;
}
}
void display() const override;
bool move() override;
void refill(int& fuel_stock);
friend class Tower;
friend class AircraftManager;
};
The code of the function generates errors that I can't understand unfortunately.
use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Aircraft; _Dp = std::default_delete<Aircraft>]’
static assertion failed: result type must be constructible from value type of input range
If anyone has an idea of how I can achieve this, I would be very grateful!
First, you have to use std::remove_if, because std::all_of returns bool, not iterator. But std::remove_if does what you want, it removes all instances that match bool predicate.
Second, your compile errors appear because you pass by value everywhere, so instead of (std::unique_ptr<Aircraft> a2) pass reference (std::unique_ptr<Aircraft> const & a2), instead [aircrafts] and [a1] pass [&aircrafts] and [&a1].
Third, inner predicate should not just return result of std::find_if (which returns iterator) but return bool, i.e. compare result of find_if to aircrafts.end().
Speed-wise your algorithm can be optimized if needed, for that you have to convert std::vector to std::unordered_set and then iterate through first map and check containment inside second set. If you don't have too many elements and speed is not of much importance then your algorithm is alright.
Final working code below:
void remove_crashed_aircraft(
std::unordered_map<const Aircraft*, size_t>& reserved_terminals,
std::vector<std::unique_ptr<Aircraft>>& aircrafts
) {
std::remove_if(reserved_terminals.begin(), reserved_terminals.end(),
[&aircrafts](auto const & a1){
return std::find_if(aircrafts.begin(), aircrafts.end(),
[&a1](auto const & a2){ return a1.first == a2.get(); })
== aircrafts.end();
}
);
}
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 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)
I have been trying to create a DLL out of the HEVC reference decoder and integrate into my application and I'm stuck with a linking error which I'm not able to solve
I have tried adding project dependencies/references. I have attached the code snippet below. I keep getting the following linking error.
HEVCDecoderDXVA.lib(HEVCRefDecImp.obj) : error LNK2019: unresolved external symbol "public: __thiscall TAppDecTop::TAppDecTop(void)" (??0TAppDecTop##QAE#XZ) referenced in function "public: __thiscall CHEVC::CHEVC(void)" (??0CHEVC##QAE#XZ)
TLibDecoder.lib(TDecGop.obj) : error LNK2001: unresolved external symbol "bool g_md5_mismatch" (?g_md5_mismatch##3_NA)
C:\HEVCDecoder3\build\Debug\HEVCDecoderDLL.dll : fatal error LNK1120: 2 unresolved externals
What I'm trying to do is to have decoder instance as a member variable in my CHEVC class
TAppDecTop m_RefDecoder;
The above line is the problem causing line , The unresolved external symbol "bool g_md5_mismatch" error is also due to this line,
In LibraryAPI.h
#ifndef _LIBRARY_API_H_
#define _LIBRARY_API_H_
namespace NSF
{
class CAPI
{
public:
virtual ~CAPI() { }
};
}
#endif // _LIBRARY_API_H_
In AppDecInf.h
#ifndef REF_DEC_INF_H
#define REF_DEC_INF_H
#include "LibraryAPI.h"
namespace NAppDecoderAPI
{
class AppDecInf : public NSF::CAPI
{
public:
virtual ~AppDecInf()
{
}
virtual int InitRefDecoder(char *fileName)=0;
virtual int TerminateRefDecoder()=0;
virtual int DecodeFrame()=0;
};
}
In HEVCRefDecImp.h
#ifndef HEVC_REF_DEC_INF_H
#define HEVC_REF_DEC_INF_H
#include "AppDecInf.h"
#include "TAppDecTop.h"
class CHEVC : public NAppDecoderAPI::AppDecInf
{
public:
CHEVC();
virtual ~CHEVC();
int InitRefDecoder(char *fileName);
int TerminateRefDecoder();
int DecodeFrame();
private:
bool temp;
TAppDecTop m_RefDecoder;
};
#endif //HEVC_REF_DEC_INF_H
In HEVCRefDecImp.cpp
#include"HEVCRefDecImp.h"
CHEVC::CHEVC()
{
temp = false;
}
CHEVC::~CHEVC()
{
}
int CHEVC::InitRefDecoder(char* fileName)
{
m_RefDecoder.create();
return(0);
}
int CHEVC::DecodeFrame()
{
m_RefDecoder.decode();
return(0);
}
int CHEVC::TerminateRefDecoder()
{
m_RefDecoder.destroy();
return(0);
}
In TAppDecTop.h
#ifndef __TAPPDECTOP__
#define __TAPPDECTOP__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "TLibVideoIO/TVideoIOYuv.h"
#include "TLibCommon/TComList.h"
#include "TLibCommon/TComPicYuv.h"
#include "TLibDecoder/TDecTop.h"
#include "TAppDecCfg.h"
//! \ingroup TAppDecoder
//! \{
// ====================================================================================================================
// Class definition
// ====================================================================================================================
/// decoder application class
class TAppDecTop : public TAppDecCfg
{
private:
// class interface
TDecTop m_cTDecTop; ///< decoder class
TVideoIOYuv m_cTVideoIOYuvReconFile; ///< reconstruction YUV class
// for output control
Bool m_abDecFlag[ MAX_GOP ]; ///< decoded flag in one GOP
Int m_iPOCLastDisplay; ///< last POC in display order
public:
TAppDecTop();
virtual ~TAppDecTop() {}
Void create (); ///< create internal members
Void destroy (); ///< destroy internal members
Void decode (); ///< main decoding function
protected:
Void xCreateDecLib (); ///< create internal classes
Void xDestroyDecLib (); ///< destroy internal classes
Void xInitDecLib (); ///< initialize decoder class
Void xWriteOutput ( TComList<TComPic*>* pcListPic , UInt tId); ///< write YUV to file
Void xFlushOutput ( TComList<TComPic*>* pcListPic ); ///< flush all remaining decoded pictures to file
};
//! \}
#endif
In TAppDecTop.cpp
#include <list>
#include <vector>
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include "TAppDecTop.h"
#include "TLibDecoder/AnnexBread.h"
#include "TLibDecoder/NALread.h"
//! \ingroup TAppDecoder
//! \{
// ====================================================================================================================
// Constructor / destructor / initialization / destroy
// ====================================================================================================================
TAppDecTop::TAppDecTop()
{
::memset (m_abDecFlag, 0, sizeof (m_abDecFlag));
m_iPOCLastDisplay = -MAX_INT;
}
Void TAppDecTop::create()
{
}
Void TAppDecTop::destroy()
{
}
// ====================================================================================================================
// Public member functions
// ====================================================================================================================
/**
- create internal class
- initialize internal class
- until the end of the bitstream, call decoding function in TDecTop class
- delete allocated buffers
- destroy internal class
.
*/
Void TAppDecTop::decode()
{
UInt uiPOC;
TComList<TComPic*>* pcListPic = NULL;
ifstream bitstreamFile(m_pchBitstreamFile, ifstream::in | ifstream::binary);
if (!bitstreamFile)
{
fprintf(stderr, "\nfailed to open bitstream file `%s' for reading\n", m_pchBitstreamFile);
exit(EXIT_FAILURE);
}
InputByteStream bytestream(bitstreamFile);
// create & initialize internal classes
xCreateDecLib();
xInitDecLib ();
m_iPOCLastDisplay += m_iSkipFrame; // set the last displayed POC correctly for skip forward.
// main decoder loop
bool recon_opened = false; // reconstruction file not yet opened. (must be performed after SPS is seen)
while (!!bitstreamFile)
{
/* location serves to work around a design fault in the decoder, whereby
* the process of reading a new slice that is the first slice of a new frame
* requires the TDecTop::decode() method to be called again with the same
* nal unit. */
streampos location = bitstreamFile.tellg();
AnnexBStats stats = AnnexBStats();
bool bPreviousPictureDecoded = false;
vector<uint8_t> nalUnit;
InputNALUnit nalu;
byteStreamNALUnit(bytestream, nalUnit, stats);
// call actual decoding function
bool bNewPicture = false;
if (nalUnit.empty())
{
/* this can happen if the following occur:
* - empty input file
* - two back-to-back start_code_prefixes
* - start_code_prefix immediately followed by EOF
*/
fprintf(stderr, "Warning: Attempt to decode an empty NAL unit\n");
}
else
{
read(nalu, nalUnit);
if(m_iMaxTemporalLayer >= 0 && nalu.m_temporalId > m_iMaxTemporalLayer)
{
if(bPreviousPictureDecoded)
{
bNewPicture = true;
bPreviousPictureDecoded = false;
}
else
{
bNewPicture = false;
}
}
else
{
bNewPicture = m_cTDecTop.decode(nalu, m_iSkipFrame, m_iPOCLastDisplay);
if (bNewPicture)
{
bitstreamFile.clear();
/* location points to the current nalunit payload[1] due to the
* need for the annexB parser to read three extra bytes.
* [1] except for the first NAL unit in the file
* (but bNewPicture doesn't happen then) */
bitstreamFile.seekg(location-streamoff(3));
bytestream.reset();
}
bPreviousPictureDecoded = true;
}
}
if (bNewPicture || !bitstreamFile)
{
m_cTDecTop.executeDeblockAndAlf(uiPOC, pcListPic, m_iSkipFrame, m_iPOCLastDisplay);
}
if( pcListPic )
{
if ( m_pchReconFile && !recon_opened )
{
if ( m_outputBitDepth == 0 )
{
m_outputBitDepth = g_uiBitDepth + g_uiBitIncrement;
}
m_cTVideoIOYuvReconFile.open( m_pchReconFile, true, m_outputBitDepth, g_uiBitDepth + g_uiBitIncrement ); // write mode
recon_opened = true;
}
if (bNewPicture && (nalu.m_nalUnitType == NAL_UNIT_CODED_SLICE_IDR))
{
xFlushOutput( pcListPic );
}
// write reconstruction to file
if(bNewPicture)
{
xWriteOutput( pcListPic, nalu.m_temporalId );
}
}
}
xFlushOutput( pcListPic );
// delete buffers
m_cTDecTop.deletePicBuffer();
// destroy internal classes
xDestroyDecLib();
}
// ====================================================================================================================
// Protected member functions
// ====================================================================================================================
Void TAppDecTop::xCreateDecLib()
{
// create decoder class
m_cTDecTop.create();
}
Void TAppDecTop::xDestroyDecLib()
{
if ( m_pchReconFile )
{
m_cTVideoIOYuvReconFile. close();
}
// destroy decoder class
m_cTDecTop.destroy();
}
Void TAppDecTop::xInitDecLib()
{
// initialize decoder class
m_cTDecTop.init();
m_cTDecTop.setPictureDigestEnabled(m_pictureDigestEnabled);
}
/** \param pcListPic list of pictures to be written to file
\todo DYN_REF_FREE should be revised
*/
Void TAppDecTop::xWriteOutput( TComList<TComPic*>* pcListPic, UInt tId )
{
TComList<TComPic*>::iterator iterPic = pcListPic->begin();
Int not_displayed = 0;
while (iterPic != pcListPic->end())
{
TComPic* pcPic = *(iterPic);
if(pcPic->getOutputMark() && pcPic->getPOC() > m_iPOCLastDisplay)
{
not_displayed++;
}
iterPic++;
}
iterPic = pcListPic->begin();
while (iterPic != pcListPic->end())
{
TComPic* pcPic = *(iterPic);
TComSPS *sps = pcPic->getSlice(0)->getSPS();
if ( pcPic->getOutputMark() && (not_displayed > pcPic->getSlice(0)->getSPS()->getNumReorderPics(tId) && pcPic->getPOC() > m_iPOCLastDisplay))
{
// write to file
not_displayed--;
if ( m_pchReconFile )
{
m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), sps->getPicCropLeftOffset(), sps->getPicCropRightOffset(), sps->getPicCropTopOffset(), sps->getPicCropBottomOffset() );
}
// update POC of display order
m_iPOCLastDisplay = pcPic->getPOC();
// erase non-referenced picture in the reference picture list after display
if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
{
#if !DYN_REF_FREE
pcPic->setReconMark(false);
// mark it should be extended later
pcPic->getPicYuvRec()->setBorderExtension( false );
#else
pcPic->destroy();
pcListPic->erase( iterPic );
iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
continue;
#endif
}
pcPic->setOutputMark(false);
}
iterPic++;
}
}
/** \param pcListPic list of pictures to be written to file
\todo DYN_REF_FREE should be revised
*/
Void TAppDecTop::xFlushOutput( TComList<TComPic*>* pcListPic )
{
if(!pcListPic)
{
return;
}
TComList<TComPic*>::iterator iterPic = pcListPic->begin();
iterPic = pcListPic->begin();
while (iterPic != pcListPic->end())
{
TComPic* pcPic = *(iterPic);
TComSPS *sps = pcPic->getSlice(0)->getSPS();
if ( pcPic->getOutputMark() )
{
// write to file
if ( m_pchReconFile )
{
m_cTVideoIOYuvReconFile.write( pcPic->getPicYuvRec(), sps->getPicCropLeftOffset(), sps->getPicCropRightOffset(), sps->getPicCropTopOffset(), sps->getPicCropBottomOffset() );
}
// update POC of display order
m_iPOCLastDisplay = pcPic->getPOC();
// erase non-referenced picture in the reference picture list after display
if ( !pcPic->getSlice(0)->isReferenced() && pcPic->getReconMark() == true )
{
#if !DYN_REF_FREE
pcPic->setReconMark(false);
// mark it should be extended later
pcPic->getPicYuvRec()->setBorderExtension( false );
#else
pcPic->destroy();
pcListPic->erase( iterPic );
iterPic = pcListPic->begin(); // to the beginning, non-efficient way, have to be revised!
continue;
#endif
}
pcPic->setOutputMark(false);
}
iterPic++;
}
pcListPic->clear();
m_iPOCLastDisplay = -MAX_INT;
}