This question already has answers here:
OpenGL object in C++ RAII class no longer works
(2 answers)
Closed 5 years ago.
Alright, so I am having a pretty tenacious issue setting up my OpenGL code. I'm trying to refactor my graphics code into a renderer object, but I can't seem to get to the bottom of a tricky GL_INVALID_OPERATION error (code 1282).
I start by creating a mesh object that initializes a loosely defined collection of OpenGL objects, and manages their lifespan in an attempt at RAII style:
struct OpenGLMesh
{
OpenGLMesh(OpenGLRenderer& renderer,
int shader_index,
const char* fpath);
~OpenGLMesh();
GLuint vbo_;
GLuint ebo_;
GLuint texture_;
std::vector<float> vertices_;
std::vector<unsigned int> indices_;
GLuint shader_id_;
GLuint mvp_id_;
};
OpenGLMesh::OpenGLMesh(OpenGLRenderer& renderer, int shader_index, const char* fpath)
{
glGenBuffers(1, &vbo_);
glGenBuffers(1, &ebo_);
glGenTextures(1, &texture_);
renderer.loadTexture(*this, fpath);
const std::vector<GLuint>& shaders = renderer.getShaders();
shader_id_ = shaders.at(shader_index);
mvp_id_ = glGetUniformLocation(shader_id_, "MVP");
}
OpenGLMesh::~OpenGLMesh()
{
glDeleteBuffers(1, &vbo_);
glDeleteBuffers(1, &ebo_);
glDeleteTextures(1, &texture_);
}
At the same time I have a renderer object that owns the majority of the initialization and rendering functions. For example, the loadTexture function in the above constructor is part of the my OpenGLRenderer class:
OpenGLRenderer::OpenGLRenderer()
{
glGenVertexArrays(1, &vao_); // allocate + assign a VAO to our handle
shaders_.push_back(loadShaders("shaders/texture.vert", "shaders/texture.frag"));
}
OpenGLRenderer::~OpenGLRenderer()
{
std::vector<GLuint>::iterator it;
for (it = shaders_.begin(); it != shaders_.end(); ++it)
{
glDeleteProgram(*it);
}
glDeleteVertexArrays(1, &vao_);
}
My first concern is that compartmentalization of these function calls may have somehow invalidated some part of my OpenGL setup calls. However, the error doesn't make an appearance until I attempt to bind my mesh's VBO.
Below is the code from a stripped down test module I built to debug this issue:
// create the renderer object
OpenGLRenderer renderer;
// create and store a mesh object
std::vector<OpenGLMesh> meshes;
meshes.push_back(OpenGLMesh(renderer, 0, "./assets/dune_glitch.png"));
// SDL Event handling loop
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao_);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo_);
printOpenGLError(); // prints out error code 1282
I've verified that it is definitely this line that breaks every time, although it doesn't seem to send a kill signal until the next iteration of the loop.
I haven't been able to find any insight on this problem - seems like glBindBuffer doesn't normally generate this kind of error. I've also made sure that the mesh.vbo_ ID still points to the same location.
For some reason, my application's stack trace doesn't play well with GDB, so I haven't been able to look at the trace as much as I would normally want to. Any advice would be a help, from debugging tips to possible sources of failure - thanks in advance!
(This is my first real post, let me know if I messed anything up!)
It the constructor of the calss OpenGLMesh the object buffers are generated (glGenBuffers). In the destructor OpenGLMesh::~OpenGLMesh the object buffers are destroyed (glDeleteBuffers).
In the following line:
meshes.push_back(OpenGLMesh(renderer, 0, "./assets/dune_glitch.png"));
you push_back the OpenGLMesh to a std::vector. This means that a temporary OpenGLMesh object is generated, an the object bffers are generated in its constructor. At this point all the data are valid and the object buffers are generated (GPU). When calling std::vector::push_back, then a new OpenGLMesh object is is generated, in the std::vector. The object is constructed by the default copy constructor and gets a copy of all the members of the first OpenGLMesh object. Immediately after this is done, the temporary OpenGLMesh object gets destroyed and the object buffers get deleted (glDeleteBuffers) by the destructor OpenGLMesh::~OpenGLMesh of the temporary object. At this point all the data are gone.
See std::vector::push_back. Put a breakpoint in the destrutor OpenGLMesh::~OpenGLMesh, then you can simply track the expiration.
You should make the class not copyable and not copy constructable, but specify a move constructor and move operator.
class OpenGLMesh
{
OpenGLMesh(const OpenGLMesh &) = delete;
OpenGLMesh & operator = (const OpenGLMesh &) = delete;
OpenGLMesh( OpenGLMesh && );
OpenGLMesh & operator = ( OpenGLMesh && );
....
};
You can quickly fix this behavior for debug reasons, by replacing
meshes.push_back(OpenGLMesh(renderer, 0, "./assets/dune_glitch.png"));
by
meshes.emplace_back(renderer, 0, "./assets/dune_glitch.png");
(see std::vector::emplace_back)
For the implementation of a move constructor and move operator see:
Move assignment operator
Move constructors
C++11 Tutorial: Introducing the Move Constructor and the Move Assignment Operator
Related
e.g. when I do
glBindBuffer(GL_ARRAY_BUFFER, _id);
glNamedBufferData(_id, size, data, static_cast<GLenum>(usage));
then program works as expected. But if I delete that first line, my program crashes and prints:
ERROR 1282 in glNamedBufferData
Likewise, if I do
glBindVertexArray(_id);
GLuint attribIndex = 0;
GLuint offset = 0;
for(const GlslType type : layout) {
const auto& attrib = GLSL_TYPES.at(type);
glVertexArrayAttribFormat(_id, attribIndex, attrib.size, static_cast<GLenum>(attrib.type), GL_FALSE, offset);
glEnableVertexArrayAttrib(_id, attribIndex);
glVertexArrayAttribBinding(_id, attribIndex, 0);
offset += attrib.size_bytes();
}
It works fine, but if I delete the glBindVertexArray then it doesn't work and prints:
ERROR 1282 in glVertexArrayAttribFormat
ERROR 1282 in glEnableVertexArrayAttrib
ERROR 1282 in glVertexArrayAttribBinding
I figured that by "naming" the VBO or VAO when calling those functions then I wouldn't have to bind it beforehand. But if I have to bind regardless, what's the benefit of these functions that require the extra name argument?
The glGen* functions create a integer name representing an object, but they don't create the object state itself (well, most of them don't). It is only when you bind those objects do they gain their state, and only after they have state can any function be called which requires them to have state. In particular, the direct state access functions.
This is why ARB_direct_state_access also includes the glCreate* functions. These functions create an integer name and the state data for objects. Therefore, you don't have to bind anything to manipulate direct state access functions, so long as you properly created the object beforehand.
I am using a library called "Pixel Game Engine", which has a Sprite and a Decal class. The documentation uses std::unique_ptr to create them, so I want to do the same to avoid any complications that may come later on.
Here is my code:
class Asset
{
private:
typedef std::unique_ptr<olc::Sprite> uniqueSprite;
typedef std::unique_ptr<olc::Decal> uniqueDecal;
private:
uniqueSprite LoadAssetImage(std::string fileName)
{
return std::make_unique<olc::Sprite>(fileName);
}
uniqueDecal MakeDecalFromSprite(uniqueSprite sprite)
{
return std::make_unique<olc::Decal>(sprite.get());
}
public:
uniqueSprite rockSprite = LoadAssetImage("rock.png"); //No Error here
uniqueDecal rockDecal = MakeDecalFromSprite(rockSprite); //Error here
};
Error:
function "std::unique_ptr<_Ty, _Dx>::unique_ptr(const std::unique_ptr<_Ty, _Dx> &) [with _Ty=olc::Sprite, _Dx=std::default_delete<olc::Sprite>]" cannot be referenced -- it is a deleted function
At first, I thought this is happening because the unique_ptr is being copied, but loading the sprite using LoadAssetImage() and assigning it to a variable works fine, so I am a little confused as to why this error is happening.
This is how the documentation loads them:
// Load Fragment Sprite
sprFragment = std::make_unique<olc::Sprite>("./gfx/tut_fragment.png");
// Create decal of fragment
decFragment = std::make_unique<olc::Decal>(sprFragment.get());
But I wanted to try something new :)
MakeDecalFromSprite passes a uniqueSprite by value, which involves making a copy. But std::unique_ptr has a deleted copy constructor so when you try to call MakeDecalFromSprite you get a compilation error.
The solution is to pass sprite by const reference instead:
uniqueDecal MakeDecalFromSprite(const uniqueSprite& sprite)
...
Then, you are not asking the compiler to make a copy.
This call:
uniqueSprite rockSprite = LoadAssetImage("rock.png");
works because of NVRO. This avoids the need to copy the function result. If this is not possible for any reason, the compiler can generate a move (std::unique_ptr is moveable).
A problem with returning a pointer from a class
I am making a project for a 3D course that involves utilizing DirectX 11. In assignments that were much smaller in scope we were encouraged to just put all the code in and around the main-file. For this project I wanted more structure, so I decided to subdivide the code into three classes: WindowHandler, D3DHandler and PipelineHandler.
D3DHandler sits in WindowHandler, and PipelineHandler sits in D3DHandler like so:
class WindowHandler
{
private:
HWND window;
MSG message
class D3DHandler()
{
private:
ID3D11Device*;
ID3D11DeviceContext*;
IDXGISwapChain*;
ID3D11RenderTargetView*;
ID3D11Texture2D*;
ID3D11DepthStencilView*;
D3D11_VIEWPORT;
class PipelineHandler()
{
private:
ID3D11VertexShader* vShader;
ID3D11PixelShader* pShader;
ID3D11InputLayout* inputLayout;
ID3D11Buffer* vertexBuffer;
}
}
}
(The classes are divided into their own .h libraries, I just wanted to compress the code a bit)
Everything ran smoothly until I tried to bind my VertexBuffer in my Render() function.
void D3DHandler::Render()
{
float clearColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
this->immediateContext->ClearRenderTargetView(this->rtv, clearColor); //Clear backbuffer
this->immediateContext->ClearDepthStencilView(this->dsView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
UINT32 vertexSize = sizeof(Vertex); //Will be the size of 8 floats, x y z, r g b, u v
UINT32 offset = 0;
this->immediateContext->VSSetShader(this->ph.GetVertexShader(), nullptr, 0);
this->immediateContext->IASetVertexBuffers(0, 1, this->ph.GetVertexBuffer(), &vertexSize, &offset);
this->immediateContext->IASetInputLayout(this->ph.GetInputLayout());
this->immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
this->immediateContext->PSSetShader(this->ph.GetPixelShader(), nullptr, 0);
//
// Draw geometry
this->immediateContext->Draw(3, 0);
}
The problem occurs at IASetVertexBuffers, where this->ph.GetVertexBuffer() gives the error
"ID3D11Buffer*" is incomaptible with parameter of type "ID3D11Buffer
*const *"
The Get-function in PipelineHandler returns a pointer to the COM object, and for VertexBuffer it looks like this:
ID3D11Buffer * PipelineHandler::GetVertexBuffer() const
{
return this->vertexBuffer;
}
From what documentation I've found, IASetVertexBuffers expects an array of buffers, so a double pointer. However, in the code I've worked with before, where the ID3D11Buffer * has been global, the same code generated no errors (and yes, most of the code I'm working so far has been wholesale copied from the last assignment in this course, just placed into classes).
I have tried to:
to remove the this-> pointer in front of the ph
Creating a new function called ID3D11Buffer & GetVertexBufferRef() const which returns return *this->vertexBuffer; using that instead.
I yet to try:
Moving vertexBuffer from the PipelineHandler and up to D3DHandler. I have a feeling that would work, but it would also disconnect the vertex buffer from the other objects that I deem to be part of the pipeline and not the context, which is something I would like to avoid.
I am grateful for any feedback I can get. I'm fairly new to programming, so any comments that aren't a solution to my problem are just as welcome.
The problem your are having is that this function signature does not take a ID3D11Buffer* interface pointer. It takes an array of ID3D11Buffer* interface pointers.
this->immediateContext->IASetVertexBuffers(0, 1, this->ph.GetVertexBuffer(), &vertexSize, &offset);
Can be any of the following:
this->immediateContext->IASetVertexBuffers(0, 1, &this->ph.GetVertexBuffer(), &vertexSize, &offset);
-or-
ID3D11Buffer* vb = this->ph.GetVertexBuffer();
this->immediateContext->IASetVertexBuffers(0, 1, &vb, &vertexSize, &offset);
-or-
ID3D11Buffer* vb[] = { this->ph.GetVertexBuffer() };
this->immediateContext->IASetVertexBuffers(0, 1, vb, &vertexSize, &offset);
This is because the Direct3D 11 API supports 'multi-stream' rendering where you have more than one Vertex Buffer referenced in the Input Layout which is merged as it is drawn. The function also takes an array of vertex sizes and offsets, which is why you had to take the address of the values vertexSize and offset instead of just passing by value. See Microsoft Docs for full details on the function signature.
This feature was first introduced back in Direct3D 9, so the best introduction to it is found here. With Direct3D 11, depending on Direct3D hardware feature level you can use up to 16 or 32 slots at once. That said, most basic rendering uses a single stream/VertexBuffer.
You should take a look at this page as to why the 'first' option above can get you into trouble with smart-pointers.
For the 'second' option, I'd recommend using C++11's auto keyboard so it would be: auto vb = this->ph.GetVertexBuffer();
The 'third' option obviously makes most sense if you are using more than one VertexBuffer for multi-stream rendering.
Note that you can never have more than one ID3D11Buffer active for the Index Buffer, so the function signature does in fact take a ID3D11Buffer* in that case and not an array. See Microsoft Docs
I sent my application for testing to several people. First tester has the same result as mine, but other twos have something strange. For some reason, image, which should be in original size at lower left corner, they see as stretched to fullscreen. Also they don't see GUI elements (however, buttons work if they are found by mouse). I will make reservation, that this isn't stretched image overlaps the buttons, I sent them version with transparent image and the buttons still aren't drawn. For GUI drawning I use Nuklear library. I will give screenshots and code that's responsible for positioning problem image. What can cause that?
[ Good behavior / Bad behavior ]
int width, height;
{
fs::path const path = fs::current_path() / "gamedata" / "images" / "logo.png";
unsigned char *const texture = stbi_load(path.u8string().c_str(), &width, &height, nullptr, STBI_rgb_alpha);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, texture);
stbi_image_free(texture);
}
...
{
float const x = -1.0f + width * 2.0f / xResolution;
float const y = -1.0f + height * 2.0f / yResolution;
float const vertices[30] = {
/* Position */ /* UV */
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, y, 0.0f, 0.0f, 1.0f,
x, y, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
x, -1.0f, 0.0f, 1.0f, 0.0f,
x, y, 0.0f, 1.0f, 1.0f
};
glBufferData(GL_ARRAY_BUFFER, 30 * sizeof(float), vertices, GL_STATIC_DRAW);
}
[ UPDATE ]
By trial and error, I realized that problem is caused by classes that are responsible for rendering the background and logo, and both of them are wrong. Separately they work as it should, but as soon as something else is added to game loop, everything breaks down.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
background.render();
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
logo.render();
nk_glfw3_render();
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
I wrote these classes myself, so most likely I missed something. Having found mistake in one, there's another, cuz they're almost identical. So far I can't determine, what exactly in these classes are wrong…
[ Background.hpp / Background.cpp ]
I found some errors in the posted code. In dramatic fashion, I will reveal the culprit last.
NULL used as an integer
For example,
glBindTexture(GL_TEXTURE_2D, NULL); // Incorrect
The glBindTexture function accepts an integer parameter, not a pointer. Here is the correct version:
glBindTexture(GL_TEXTURE_2D, 0); // Correct
This also applies to glBindBuffer and glBindVertexArray.
Nullary constructor is defined explicit
The explicit keyword only affects unary constructors (constructors which take one parameter). It does not affect constructors with any other number of parameters.
explicit Background() noexcept; // "explicit" does not do anything.
Background() noexcept; // Exact same declaration as above.
Constructor is incorrectly defined as noexcept
The noexcept keyword means "this function will never throw an exception". However it contains the following code which can throw:
new Shader("image")
According to the standard, this can throw a std::bad_alloc. So the noexcept annotation is incorrect. See Can the C++ `new` operator ever throw an exception in real life?
On a more practical note, the constructor reads an image from disk. This is likely to fail, and throwing an exception is a reasonable way of handling this.
The noexcept keyword is not particularly useful here. Perhaps the compiler can generate slightly less code at the call site, but this is likely to make at most an infinitesimal difference because the constructor is cold code (cold = not called often). The noexcept qualifier is mostly just useful for choosing between different generic algorithms, see What is noexcept useful for?
No error handling
Remember that stdbi_load will return NULL if an error occurs. This case is not handled.
Rule of three is violated
The Background class does not define a copy constructor or copy assignment operator even though it defines a destructor. While this is not guaranteed to make your program incorrect, it is kind of like leaving a loaded and cocked gun on the kitchen counter and hoping nobody touches it. This is called the Rule of Three and it is simple to fix. Add a deleted copy constructor and copy assignment operator.
// These three go together, either define all of them or none.
// Hence, "rule of three".
Background(const Background &) = delete;
Background &operator=(const Background &) = delete;
~Background();
See What is The Rule of Three?
Buffer is incorrectly deleted
Here is the line:
glDeleteBuffers(1, &VBO);
The short version... you should move this into Background::~Background().
The long version... when you delete the buffer, it is not removed from the VAO but the name can get reused immediately. According to the OpenGL 4.6 spec 5.1.2:
When a buffer, texture, or renderbuffer object is deleted, it is ... detached from any attachments of container objects that are bound to the current context, ...
So, because the VAO is not currently bound, deleting the VBO does not remove the VBO from the VAO (if the VAO were bound, this would be different). But, section 5.1.3:
When a buffer, texture, sampler, renderbuffer, query, or sync object is deleted, its name immediately becomes invalid (e.g. is marked unused), but the underlying object will not be deleted until it is no longer in use.
So the VBO will remain, but the name may be reused. This means that a later call to glGenBuffers might give you the same name. Then, when you call glBufferData, it overwrites the data in both your background and your logo. Or, glGenBuffers might give you a completely different buffer name. This is completely implementation-dependent, and this explains why you see different behavior on different computers.
As a rule, I would avoid calling glDeleteBuffers until I am done using the buffer. You can technically call glDeleteBuffers earlier, but it means you can get the same buffer back from glGenBuffers.
when i run my program it compiles fine but when it runs i get this box which stops my program. the box says this Unhandled exception at 0x0039e9a7 in Mon.exe: 0xC0000005: Access violation reading location 0xcdcdcdcd. i don't even know what that means. when it breaks it point at this function.
void CXFileEntity::SetAnimationSet(unsigned int index)
{
if (index==m_currentAnimationSet)
return;
if (index>=m_numAnimationSets)
index=0;
// Remember current animation
m_currentAnimationSet=index;
// Get the animation set from the controller
LPD3DXANIMATIONSET set;
IT BREAKS HERE>>>>m_animController->GetAnimationSet(m_currentAnimationSet, &set );
// Note: for a smooth transition between animation sets we can use two tracks and assign the new set to the track
// not currently playing then insert Keys into the KeyTrack to do the transition between the tracks
// tracks can be mixed together so we can gradually change into the new animation
// Alternate tracks
DWORD newTrack = ( m_currentTrack == 0 ? 1 : 0 );
// Assign to our track
m_animController->SetTrackAnimationSet( newTrack, set );
set->Release();
// Clear any track events currently assigned to our two tracks
m_animController->UnkeyAllTrackEvents( m_currentTrack );
m_animController->UnkeyAllTrackEvents( newTrack );
// Add an event key to disable the currently playing track kMoveTransitionTime seconds in the future
m_animController->KeyTrackEnable( m_currentTrack, FALSE, m_currentTime + kMoveTransitionTime );
// Add an event key to change the speed right away so the animation completes in kMoveTransitionTime seconds
m_animController->KeyTrackSpeed( m_currentTrack, 0.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Add an event to change the weighting of the current track (the effect it has blended with the secon track)
m_animController->KeyTrackWeight( m_currentTrack, 0.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Enable the new track
m_animController->SetTrackEnable( newTrack, TRUE );
// Add an event key to set the speed of the track
m_animController->KeyTrackSpeed( newTrack, 1.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Add an event to change the weighting of the current track (the effect it has blended with the first track)
// As you can see this will go from 0 effect to total effect(1.0f) in kMoveTransitionTime seconds and the first track goes from
// total to 0.0f in the same time.
m_animController->KeyTrackWeight( newTrack, 1.0f, m_currentTime, kMoveTransitionTime, D3DXTRANSITION_LINEAR );
// Remember current track
m_currentTrack = newTrack;
}
any idea?
UPDATE
this is the class
class CXFileEntity
{
private:
LPDIRECT3DDEVICE9 m_d3dDevice; // note: a pointer copy (not a good idea but for simplicities sake)
// Direct3D objects required for animation
LPD3DXFRAME m_frameRoot;
LPD3DXANIMATIONCONTROLLER m_animController;
D3DXMESHCONTAINER_EXTENDED* m_firstMesh;
// Bone data
D3DXMATRIX *m_boneMatrices;
UINT m_maxBones;
// Animation variables
unsigned int m_currentAnimationSet;
unsigned int m_numAnimationSets;
unsigned int m_currentTrack;
float m_currentTime;
float m_speedAdjust;
// Bounding sphere (for camera placement)
D3DXVECTOR3 m_sphereCentre;
float m_sphereRadius;
std::string m_filename;
void UpdateFrameMatrices(const D3DXFRAME *frameBase, const D3DXMATRIX *parentMatrix);
void UpdateSkinnedMesh(const D3DXFRAME *frameBase);
void DrawFrame(LPD3DXFRAME frame) const;
void DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) const;
void SetupBoneMatrices(D3DXFRAME_EXTENDED *pFrame/*, LPD3DXMATRIX pParentMatrix*/);
public:
CXFileEntity(LPDIRECT3DDEVICE9 d3dDevice);
~CXFileEntity(void);
bool Load(const std::string &filename);
void FrameMove(float elapsedTime,const D3DXMATRIX *matWorld);
void Render() const;
void SetAnimationSet(unsigned int index);
void NextAnimation();
void AnimateFaster();
void AnimateSlower();
D3DXVECTOR3 GetInitialCameraPosition() const;
unsigned int GetCurrentAnimationSet() const {return m_currentAnimationSet;}
std::string GetAnimationSetName(unsigned int index);
std::string GetFilename() const {return m_filename;}
};
im releasing m_animController in the destructor
0xC0000005: Access violation reading
location 0xcdcdcdcd.
Well it's simple :
Access violation is an error where you tried to access some memory that are allowed to be accessed. For example you might be trying to use a null pointer.
Here the 0xcdcdcdcd part is a special adress put by visual studio when a pointer have been deleted (or more precisely, the object pointed by the pointer is destroyed and the pointer is set to this value) or non-initialized > (edit: I'm not sure anymore, will have to check the VS documentation). That's true only in Debug mode if my memory is correct.
So here, m_animController is in a wrong state (as it seems that it's the unique pointer of the expression where it crashes).
First, I would suggest that you make sure that delete have not been called before on this pointer. It might be obvious or it might be that you call delete in the object destructor and you didn't see that this object have bee destroyed or copied. If your object (CXFileEntity) must not be copied, make sure it can't be (by inheriting from boost::noncopiable or by putting it's copy constructor and copy operator in private with no implementation).
Next, if you really have to use raw pointers (instead of references or smart pointers) you'd better check all your pointers (and other contextual values) at the start of each function, using assertions (look for assertions in google and stackoverflow, there is a lot of discussions about that). Even better: check that pointers are valid each time you get them from functions. That will help you track early when a a pointer got in a state you didn't expect.
You attempted to access memory to which you do not have access. Most commonly this is because you are using a pointer that you have not initialized and it points to an address that's not in your process's memory space.
You should make sure that m_animController is initialized (and pointing to a valid object) before you dereference it with the -> operator.
You have a bad pointer somewhere. Based on the line where it breaks, I'm guessing m_animController has a bad value. Check that m_animController is initialized to a default value. And make sure you aren't deleting it somewhere before using it.
Note: 0xcdcdcdcd is a common value that some debuggers will initialize invalid pointers with, but it's not guaranteed.