Trouble creating pointer to abstract class - c++

I coded some smiley faces into my app recently, but I'm having trouble calling it in my option interface. The reason I'm wanting to call it from optioninterface is I want to add 2 sets of emojis, and if the value of Setting.nEmoji is 0 or 1 call a different set. The function loademojis() gets called when the application starts (it's technically coded in the interface solution). I can call it from a function that handles user input, but it generated horrible lag, I assume because each time a letter was typed, it cleared the array and loaded the emojis in again. So long story short, I was wondering if there's any way at all to create a pointer to a abstract class so I could call this from my option menu. Everytime I create a pointer and call it from theoption menu it crashes. Here's how I'm creating the pointer
MDrawContext* pDC
void MDrawContext::LoadEmojis()
{
if (Z_VIDEO_EMOJIS == 1)
{
m_Emoji[";)"] = "wink.png";
m_Emoji[":)"] = "smile.png";
m_Emoji[":D"] = "biggrin.png";
m_Emoji[":("] = "frown.png";
m_Emoji[":O"] = "eek.png";
m_Emoji[":P"] = "tongue.png";
m_Emoji[":?"] = "confused.png";
m_Emoji[":4"] = "cool.png";
m_Emoji[":3"] = "redface.png";
m_Emoji[":#"] = "mad.png";
m_Emoji[":I"] = "rolleyes.png";
m_Emoji[":K"] = "kappa.png";
}
else
{
m_Emoji[";)"] = "wink2.png";
m_Emoji[":)"] = "smile2.png";
m_Emoji[":D"] = "biggrin2.png";
m_Emoji[":("] = "frown2.png";
m_Emoji[":O"] = "eek2.png";
m_Emoji[":P"] = "tongue2.png";
}
}
//custom: reloademojis allows players to choose between ios/forum emojis
void MDrawContext::ReloadEmojis()
{
m_Emoji[";)"].clear();
m_Emoji[":)"].clear();
m_Emoji[":D"].clear();
m_Emoji[":("].clear();
m_Emoji[":O"].clear();
m_Emoji[":P"].clear();
m_Emoji[":?"].clear();
m_Emoji[":4"].clear();
m_Emoji[":3"].clear();
m_Emoji[":#"].clear();
m_Emoji[":I"].clear();
m_Emoji[":K"].clear();
LoadEmojis();
}
//Calling the pointer (different cpp)
int nEmojiType = 0;
if(nEmojiType != Z_VIDEO_EMOJI)
{
pDC->ReloadEmojis();
nEmojiType = Z_VIDEO_EMOJI;
}

Related

Using Vulkan memory allocator with Volk

I'm currently trying to use Vulkan memory allocator with the meta loader Volk
here is the link of the two: https://github.com/zeux/volk
https://gpuopen.com/vulkan-memory-allocator/
But I have trouble with creating the VmaAllocator, here is my code:
void VulkApp::Init(PipelineFlags t_Conf, entt::registry& t_reg)
{
volkInitialize();
WindowProps props = {};
props.Height = 600;
props.Width = 800;
props.Title = "Engine";
currentWindow = EngWindow::Create(props);
//Create all physical, logical, instance for vulkan
Prepare();
VolkDeviceTable test;
volkLoadDeviceTable(&test, m_LogicalDevice->GetVkDevice());
VmaAllocatorCreateInfo allocatorCreateInfo = {};
allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_2;
allocatorCreateInfo.physicalDevice = m_PhysicalDevice->GetVkPhysicalDevice();
allocatorCreateInfo.device = m_LogicalDevice->GetVkDevice();
allocatorCreateInfo.instance = m_Instance->GetRawVkInstance();
allocatorCreateInfo.pVulkanFunctions = reinterpret_cast<const VmaVulkanFunctions*> (&test);
VmaAllocator allocator;
vmaCreateAllocator(&allocatorCreateInfo, &allocator);
BuildRenderPipelines(t_Conf, t_reg);
}
void VulkApp::Prepare()
{
m_Instance = std::make_unique<VulkInst>();
volkLoadInstance(m_Instance->GetRawVkInstance());
currentWindow->CreateSurface(m_Instance->GetRawVkInstance(), &m_Surface);
m_PhysicalDevice = std::make_unique<PhysicalDevice>(*m_Instance);
m_LogicalDevice = std::make_unique<LogicalDevice>(*m_Instance, *m_PhysicalDevice, m_Surface);
volkLoadDevice(m_LogicalDevice->GetVkDevice());
m_SwapChain = std::make_unique<SwapChain>(ChooseSwapExtent(), *m_LogicalDevice, *m_PhysicalDevice, m_Surface);
GraphicsHelpers::CreateCommandPool(m_CommandPool, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT); //TODO: added Transient bit
CreateFrameSyncResources();
/*
Create Camera
*/
BuildSwapChainResources();
}
I don't have any error when i build, but when i execute, the VmaCreateAllocator return an error:
Exception raised at 0x00007FFAB0CD836B (VkLayer_khronos_validation.dll) in My_Game.exe : 0xC0000005 : access violation reading location 0x0000000000000120.
Not very useful, but it stops on the line 14082 of the file vk_mem_alloc.h:
(*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
The program check all the vulkan validation function so my vulkan function table must be good. But still the allocation fail.
I'm sorry i don't put a 'minimal' code, but with vulkan, even the minimum is really long. So, as a first test, maybe some of you have an insight of the error?
If you use a loader like Volk, you need to provide all memory related Vulkan function pointers used by VMA yourself.
This is done via the pVulkanFunctions member of the VmaAllocatorCreateInfo structure.
So when creating your VmaAllactor you set the function pointer in that to those fetched via Volk like this:
VmaVulkanFunctions vma_vulkan_func{};
vma_vulkan_func.vkAllocateMemory = vkAllocateMemory;
vma_vulkan_func.vkBindBufferMemory = vkBindBufferMemory;
vma_vulkan_func.vkBindImageMemory = vkBindImageMemory;
vma_vulkan_func.vkCreateBuffer = vkCreateBuffer;
vma_vulkan_func.vkCreateImage = vkCreateImage;
vma_vulkan_func.vkDestroyBuffer = vkDestroyBuffer;
vma_vulkan_func.vkDestroyImage = vkDestroyImage;
vma_vulkan_func.vkFlushMappedMemoryRanges = vkFlushMappedMemoryRanges;
vma_vulkan_func.vkFreeMemory = vkFreeMemory;
vma_vulkan_func.vkGetBufferMemoryRequirements = vkGetBufferMemoryRequirements;
vma_vulkan_func.vkGetImageMemoryRequirements = vkGetImageMemoryRequirements;
vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties = vkGetPhysicalDeviceMemoryProperties;
vma_vulkan_func.vkGetPhysicalDeviceProperties = vkGetPhysicalDeviceProperties;
vma_vulkan_func.vkInvalidateMappedMemoryRanges = vkInvalidateMappedMemoryRanges;
vma_vulkan_func.vkMapMemory = vkMapMemory;
vma_vulkan_func.vkUnmapMemory = vkUnmapMemory;
vma_vulkan_func.vkCmdCopyBuffer = vkCmdCopyBuffer;
And then pass those to the create info:
VmaAllocatorCreateInfo allocator_info{};
...
allocator_info.pVulkanFunctions = &vma_vulkan_func;

Converting an unruly dependency injection model with a service locator

I've been using DI for a game engine project for a while and I just hit a wall; given the below order of creation: The job system does not depend on anything and everything depends on the file logger. It makes sense to create the job system, then the file logger, then pass the created references for each dependency down to its dependents' constructors.
App::App(const std::string& cmdString)
: EngineSubsystem()
, _theJobSystem{std::make_unique<JobSystem>(-1, static_cast<std::size_t>(JobType::Max), new std::condition_variable)}
, _theFileLogger{std::make_unique<FileLogger>(*_theJobSystem.get(), "game")}
, _theConfig{std::make_unique<Config>(KeyValueParser{cmdString})}
, _theRenderer{std::make_unique<Renderer>(*_theJobSystem.get(), *_theFileLogger.get(), *_theConfig.get())}
, _theInputSystem{std::make_unique<InputSystem>(*_theFileLogger.get(), *_theRenderer.get())}
, _theUI{std::make_unique<UISystem>(*_theFileLogger.get(), *_theRenderer.get(), *_theInputSystem.get())}
, _theConsole{std::make_unique<Console>(*_theFileLogger.get(), *_theRenderer.get())}
, _theAudioSystem{std::make_unique<AudioSystem>(*_theFileLogger.get()) }
, _theGame{std::make_unique<Game>()}
{
SetupEngineSystemPointers();
SetupEngineSystemChainOfResponsibility();
LogSystemDescription();
}
void App::SetupEngineSystemPointers() {
g_theJobSystem = _theJobSystem.get();
g_theFileLogger = _theFileLogger.get();
g_theConfig = _theConfig.get();
g_theRenderer = _theRenderer.get();
g_theUISystem = _theUI.get();
g_theConsole = _theConsole.get();
g_theInputSystem = _theInputSystem.get();
g_theAudioSystem = _theAudioSystem.get();
g_theGame = _theGame.get();
g_theApp = this;
}
void App::SetupEngineSystemChainOfResponsibility() {
g_theConsole->SetNextHandler(g_theUISystem);
g_theUISystem->SetNextHandler(g_theInputSystem);
g_theInputSystem->SetNextHandler(g_theApp);
g_theApp->SetNextHandler(nullptr);
g_theSubsystemHead = g_theConsole;
}
As you can see, passing the different subsystems around to the other subsystem constructors is starting to get messy. In particular when dealing with jobs, logging, console commands, UI, configuration, and audio (and physics, not pictured).
(Side note: These are going to eventually be replaced with interfaces created via factories for cross-compatibility, i.e. the Renderer is strictly a DirectX/Windows-only renderer but I want to eventually support OpenGL/Linux; that's why everything is passed around as references and created as pointers instead of a concrete types)
I've run in to situations where pretty much all the subsystems are in some way dependent on every other subsystem.
But, due to construction-order problems, Dependency Injection does not work because one or more of the required-to-exist subsystems hasn't been constructed yet. Same problem with two-phase construction: the subsystem may not have been initialized by the time it's needed further downstream.
I looked in to the service locator pattern and this question deems it a bad idea, but the game industry likes using bad ideas (like global variables to every subsystem for game-specific code to use) if they work.
Would converting to a service locator fix this problem?
What other implementations do you know of that could also fix the issue?
I ultimately went with the ServiceLocator pattern, deriving every subsystem that was a dependency as a Service:
App::App(const std::string& cmdString)
: EngineSubsystem()
, _theConfig{std::make_unique<Config>(KeyValueParser{cmdString})}
{
SetupEngineSystemPointers();
SetupEngineSystemChainOfResponsibility();
LogSystemDescription();
}
void App::SetupEngineSystemPointers() {
ServiceLocator::provide(*static_cast<IConfigService*>(_theConfig.get()));
_theJobSystem = std::make_unique<JobSystem>(-1, static_cast<std::size_t>(JobType::Max), new std::condition_variable);
ServiceLocator::provide(*static_cast<IJobSystemService*>(_theJobSystem.get()));
_theFileLogger = std::make_unique<FileLogger>("game");
ServiceLocator::provide(*static_cast<IFileLoggerService*>(_theFileLogger.get()));
_theRenderer = std::make_unique<Renderer>();
ServiceLocator::provide(*static_cast<IRendererService*>(_theRenderer.get()));
_theInputSystem = std::make_unique<InputSystem>();
ServiceLocator::provide(*static_cast<IInputService*>(_theInputSystem.get()));
_theAudioSystem = std::make_unique<AudioSystem>();
ServiceLocator::provide(*static_cast<IAudioService*>(_theAudioSystem.get()));
_theUI = std::make_unique<UISystem>();
_theConsole = std::make_unique<Console>();
_theGame = std::make_unique<Game>();
g_theJobSystem = _theJobSystem.get();
g_theFileLogger = _theFileLogger.get();
g_theConfig = _theConfig.get();
g_theRenderer = _theRenderer.get();
g_theUISystem = _theUI.get();
g_theConsole = _theConsole.get();
g_theInputSystem = _theInputSystem.get();
g_theAudioSystem = _theAudioSystem.get();
g_theGame = _theGame.get();
g_theApp = this;
}
void App::SetupEngineSystemChainOfResponsibility() {
g_theConsole->SetNextHandler(g_theUISystem);
g_theUISystem->SetNextHandler(g_theInputSystem);
g_theInputSystem->SetNextHandler(g_theRenderer);
g_theRenderer->SetNextHandler(g_theApp);
g_theApp->SetNextHandler(nullptr);
g_theSubsystemHead = g_theConsole;
}

Qjson handling an returned array of ojbects

I'm using Qjson to parse a json object that is returned from a web service. I'm stuck on handling an array of complex ojects.
At the first level the web service returns a map consisting of "error", "id", and "return". If there are no errors I can get the first level value by using
nestedMap = m_jsonObject["result"].toMap();
group = new Group();
group->Caption = nestedMap["Caption"].toString();
group->CollectionCount = nestedMap["CollectionCount"].toInt();
I can even get a date item value that is at the second level using
group->ModifiedOn = nestedMap["ModifiedOn"].toMap()["Value"].toDateTime();
I have an object called "Elements" that consists of 29 key-value pairs. The web service is returning an array of these "Elements" and I am unable to find the right way to parse it. In the header file the container for the elements is defined as
QList<GroupElement> Elements;
The line
group->Elements = nestedMap["Elements"].toList();
causes the compiler to throw an error 'error: no match for 'operator=' in '((MyClass*)this)->MyClass::group->Group::Elements = QVariant::toMap() const()'
I would like to learn the correct syntax to put this element into the class.
Update: I wrote another function to convert the QVariantMap object to a
first:
The group-> Elements object was changed to a
class ParentClass{
QList<SharedDataPointer<Address> > Elements;
other class memmbers...
};
Second:
A method to convert the QMap object to an Address object was created
QSharedDataPointer<Address>
API_1_6::mapToAddress(QVariantMap o)
{
QSharedDataPointer<Address> address (new Address());
address-> FirstName = o["FirstName"].toString();
address->LastName = o["LastName"].toString();
address->CompanyName = o["CompanyName"].toString();
address->Street = o["Street"].toString();
address->Street2 = o["Street2"].toString();
address->City = o["City"].toString();
address->Zip = o["Zip"].toString();
address-> State = o["State"].toString();
address->Country = o["Country"].toString();
address->Phone = o["Phone"].toString();
address->Phone2 = o["Phone2"].toString();
address-> Fax = o["Fax"].toString();
address-> Url = o["Url"].toString();
address->Email = o["Email"].toString();
address->Other = o["Other"].toString();
return address;
}
third: In the code, foreach is used to walk through the list and create and store the new objects
// get the list of the elements
elementsList = nestedMap["Elements"].toList();
// Add the element, converted to the new type, to the Elements object of the'parent' class
foreach(QVariant qElement, elementsList){
group-> Elements.append(mapToAddress(qElement))
}

Dynamics GP Web Services: SalesInvoice Creation with Lot Allocation

I'm trying to use the following code to create a new SalesInvoice based on an existing SalesOrder:
SalesInvoice invoice = new SalesInvoice();
invoice.DocumentTypeKey = new SalesDocumentTypeKey { Type = SalesDocumentType.Invoice };
invoice.CustomerKey = originalOrder.CustomerKey;
invoice.BatchKey = originalOrder.BatchKey;
invoice.Terms = new SalesTerms { DiscountTakenAmount = new MoneyAmount { Value = 0, Currency = "USD", DecimalDigits = 2 }, DiscountAvailableAmount = new MoneyAmount { Value = 0, Currency = "USD", DecimalDigits = 0 } };
invoice.OriginalSalesDocumentKey = originalOrder.Key;
List<SalesInvoiceLine> lineList = new List<SalesInvoiceLine>();
for (int i = 0; i < originalOrder.Lines.Length; i++)
{
SalesInvoiceLine line = new SalesInvoiceLine();
line.ItemKey = originalOrder.Lines[i].ItemKey;
line.Key = new SalesLineKey { LineSequenceNumber = originalOrder.Lines[i].Key.LineSequenceNumber; }
SalesLineLot lot = new SalesLineLot();
lot.LotNumber = originalOrder.Lines[i].Lots[0].LotNumber;
lot.Quantity = new Quantity { Value = 2200 };
lot.Key = new SalesLineLotKey { SequenceNumber = originalOrder.Lines[i].Lots[0].Key.SequenceNumber };
line.Lots = new SalesLineLot[] { lot };
line.Quantity = new Quantity { Value = 2200 };
lineList.Add(line);
}
invoice.Lines = lineList.ToArray();
DynamicsWS.CreateSalesInvoice(invoice, DynamicsContext, DynamicsWS.GetPolicyByOperation("CreateSalesInvoice", DynamicsContext));
When executed, I receive the following error:
SQL Server Exception: Operation expects a parameter which was not supplied.
And the more detailed exception from the Exception Console in Dynamics:
Procedure or function 'taSopLotAuto' expects parameter '#I_vLNITMSEQ',
which was not supplied.
After a considerable amount of digging through Google, I discovered a few things.
'taSopLotAuto' is an eConnect procedure within the Sales Order Processing component that attempts to automatically fill lots. I do not want the lots automatically filled, which is why I try to fill them manually in the code. I've also modified the CreateSalesInvoice policy from Automatic lot fulfillment to Manual lot fulfillment for the GP web services user, but that didn't change which eConnect procedure was called.
'#I_vLNITMSEQ' refers to the LineSequenceNumber. The LineSequenceNumber and SequenceNumber (of the Lot itself) must match. In my case they are both the default: 16384. Not only is this parameter set in the code above, but it also appears in the SOAP message that the server attempted to process - hardly "not supplied."
I can create an invoice sans line items without a hitch, but if I add line items it fails. I do not understand why I am receiving an error for a missing parameter that is clearly present.
Any ideas on how to successfully create a SalesInvoice through Dynamics GP 10.0 Web Services?
Maybe you mess to add the line key to the lot:
lot.Key = new SalesLineKey();
lot.Key.SalesDocumentKey = new SalesDocumentKey();
lot.Key.SalesDocumentKey.Id = seq.ToString();

Subsonic 3 Save() then Update()?

I need to get the primary key for a row and then insert it into one of the other columns in a string.
So I've tried to do it something like this:
newsObj = new news();
newsObj.name = "test"
newsObj.Save();
newsObj.url = String.Format("blah.aspx?p={0}",newsObj.col_id);
newsObj.Save();
But it doesn't treat it as the same data object so newsObj.col_id always comes back as a zero. Is there another way of doing this? I tried this on another page and to get it to work I had to set newsObj.SetIsLoaded(true);
This is the actual block of code:
page p;
if (pageId > 0)
p = new page(ps => ps.page_id == pageId);
else
p = new page();
if (publish)
p.page_published = 1;
if (User.IsInRole("administrator"))
p.page_approved = 1;
p.page_section = staticParent.page_section;
p.page_name = PageName.Text;
p.page_parent = parentPageId;
p.page_last_modified_date = DateTime.Now;
p.page_last_modified_by = (Guid)Membership.GetUser().ProviderUserKey;
p.Add();
string urlString = String.Empty;
if (parentPageId > 0)
{
urlString = Regex.Replace(staticParent.page_url, "(.aspx).*$", "$1"); // We just want the static page URL (blah.aspx)
p.page_url = String.Format("{0}?p={1}", urlString, p.page_id);
}
p.Save();
If I hover the p.Save(); I can see the correct values in the object but the DB is never updated and there is no exception.
Thanks!
I faced the same problem with that :
po oPo = new po();
oPo.name ="test";
oPo.save(); //till now it works.
oPo.name = "test2";
oPo.save(); //not really working, it's not saving the data since isLoaded is set to false
and the columns are not considered dirty.
it's a bug in the ActiveRecord.tt for version 3.0.0.3.
In the method public void Add(IDataProvider provider)
immediately after SetIsNew(false);
there should be : SetIsLoaded(true);
the reason why the save is not working the second time is because the object can't get dirty if it is not loaded. By adding the SetIsLoaded(true) in the ActiveRecord.tt, when you are going to do run custom tool, it's gonna regenerate the .cs perfectly.