Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

sorry in advance for the large chunk of code. Basically when placed in the same file this works fine, but if placed in separate files (and I have tested this) just after Init() is called, the pointer to ID3D10* device's value is suddenly 0x00000000. If it's all in the same file, the device pointer has a memory address all the way through. I'm really stumped here. Also wasn't quite sure whether this was a gamedev or stackoverflow question so sorry if it's in the wrong place. SORRY IN ADVANCE FOR THE AMOUNT OF CODE!

file that makes the calls:

#include <d3d10.h>
#include <d3dx10.h>
#include "direct3D.h"
#include "game.h"
#include "cube.h"

Cube* cube1;
void test();
//called once
void Initialise(HWND hWnd)
{
    initD3D(hWnd);
    init_pipeline();
    test();
    //cube1->Init();
    Init();
}

Direc3D.cpp

// include the basic windows header files and the Direct3D header files
#include <d3d10.h>
#include <d3dx10.h>
#include "direct3D.h"
#include "Globals.h"

// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC scd;

ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));

scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferDesc.Width = SCREEN_WIDTH;
scd.BufferDesc.Height = SCREEN_HEIGHT;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = 1;
scd.SampleDesc.Quality = 0;
scd.Windowed = TRUE;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

// create a device class and swap chain class using the information in the scd struct
D3D10CreateDeviceAndSwapChain(NULL,
                              D3D10_DRIVER_TYPE_HARDWARE,
                              NULL,
                              0,
                              D3D10_SDK_VERSION,
                              &scd,
                              &swapchain,
                              &device);


// create a texture for the depth buffer
D3D10_TEXTURE2D_DESC zbd;
ZeroMemory(&zbd, sizeof(zbd));
zbd.Width = SCREEN_WIDTH;    // set the width of the depth buffer
zbd.Height = SCREEN_HEIGHT;    // set the height of the depth buffer
zbd.ArraySize = 1;    // we are only creating one texture
zbd.SampleDesc.Count = 1;    // no multi-sampling
zbd.Format = DXGI_FORMAT_D32_FLOAT;    // one 32-bit float per pixel
zbd.BindFlags = D3D10_BIND_DEPTH_STENCIL;    // texture is to be used as a depth buffer
ID3D10Texture2D* pDepthBuffer;
device->CreateTexture2D(&zbd, NULL, &pDepthBuffer);    // create the texture

// create the depth buffer
D3D10_DEPTH_STENCIL_VIEW_DESC dsvd;
ZeroMemory(&dsvd, sizeof(dsvd));
dsvd.Format = DXGI_FORMAT_D32_FLOAT;    // one 32-bit float per pixel
dsvd.ViewDimension = D3D10_DSV_DIMENSION_TEXTURE2D;    // depth buffer is a 2D texture
device->CreateDepthStencilView(pDepthBuffer, &dsvd, &dsv);    // create the depth buffer
pDepthBuffer->Release();    // release the texture once the depth buffer is made

// get the address of the back buffer and use it to create the render target
ID3D10Texture2D* pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (LPVOID*)&pBackBuffer);
device->CreateRenderTargetView(pBackBuffer, NULL, &rtv);
pBackBuffer->Release();

// set the back buffer as the render target
device->OMSetRenderTargets(1, &rtv, dsv);

D3D10_VIEWPORT viewport;    // create a struct to hold the viewport data

ZeroMemory(&viewport, sizeof(D3D10_VIEWPORT));    // clear out the struct for use

viewport.TopLeftX = 0;    // set the left to 0
viewport.TopLeftY = 0;    // set the top to 0
viewport.Width = SCREEN_WIDTH;    // set the width to the window's width
viewport.Height = SCREEN_HEIGHT;    // set the height to the window's height
viewport.MinDepth = 0;    // the closest an object can be on the depth buffer is 0.0
viewport.MaxDepth = 1;    // the farthest an object can be on the depth buffer is 1.0

device->RSSetViewports(1, &viewport);    // set the viewport
}

// this is the function used to render a single frame
void render_frame()
{
// clear the window to a deep blue and clear the depth buffer to 1.0f
device->ClearRenderTargetView(rtv, D3DXCOLOR(0.0f, 0.2f, 0.4f, 1.0f));
device->ClearDepthStencilView(dsv, D3D10_CLEAR_DEPTH, 1.0f, 0);

    // select which input layout we are using
    device->IASetInputLayout(pVertexLayout);

    // select which primtive type we are using
    device->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    // select which vertex buffer and index buffer to display
    UINT stride = sizeof(VERTEX);
    UINT offset = 0;
    device->IASetVertexBuffers(0, 1, &pBuffer, &stride, &offset);
    device->IASetIndexBuffer(iBuffer, DXGI_FORMAT_R32_UINT, 0);

    D3DXMATRIX matRotate, matView, matProjection, matFinal;

    // increase the time varaible and send to the effect
    static float Time = 0.0f; Time += 0.001f;

    // create a rotation matrix
    D3DXMatrixRotationY(&matRotate, Time);

    // create a view matrix
    D3DXMatrixLookAtLH(&matView,
                       &D3DXVECTOR3(0.0f, 9.0f, 24.0f),    // the camera position
                       &D3DXVECTOR3(0.0f, 0.0f, 0.0f),    // the look-at position
                       &D3DXVECTOR3(0.0f, 1.0f, 0.0f));    // the up direction

    // create a projection matrix
    D3DXMatrixPerspectiveFovLH(&matProjection,
                           (float)D3DXToRadian(45),    // the horizontal field of view
                           (FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
                           1.0f,    // the near view-plane
                           100.0f);    // the far view-plane

    // combine the matrices and render
    matFinal = matRotate * matView * matProjection;
    pTransform->SetMatrix(&matFinal._11); 
    pPass->Apply(0);
    device->DrawIndexed(36, 0, 0);

// display the rendered frame
swapchain->Present(0, 0);
}

// this function sets up the pipeline for rendering
void init_pipeline()
{
// load the effect file
D3DX10CreateEffectFromFile(L"effect.fx", 0, 0,
                           "fx_4_0", 0, 0,
                           device, 0, 0,
                           &pEffect, 0, 0);

// get the technique and the pass
pTechnique = pEffect->GetTechniqueByIndex(0);
pPass = pTechnique->GetPassByIndex(0);
pPass->GetDesc(&PassDesc);

// get the Transform effect variable
pTransform = pEffect->GetVariableByName("Transform")->AsMatrix();

// create the input element descriptions
D3D10_INPUT_ELEMENT_DESC Layout[] =
{
    // first input element: position
    {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT,
        D3D10_INPUT_PER_VERTEX_DATA, 0},

    // second input element: color
    {"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT,
        D3D10_INPUT_PER_VERTEX_DATA, 0}
};

// use the input element descriptions to create the input layout
device->CreateInputLayout(Layout,
                          2,
                          PassDesc.pIAInputSignature,
                          PassDesc.IAInputSignatureSize,
                          &pVertexLayout);
}

// this is the function that cleans up Direct3D and COM
void cleanD3D()
{
swapchain->SetFullscreenState(FALSE, NULL);    // switch to windowed mode

//pBuffer->Release();    // close and release the vertex buffer
pVertexLayout->Release();    // close and release the input layout object
swapchain->Release();    // close and release the swap chain
rtv->Release();    // close and release the render target view
device->Release();    // close and release the 3D device
}

void Init()
{
// create eight vertices to represent the corners of the cube
VERTEX OurVertices[] =
{
    {D3DXVECTOR3(-1.0f, 1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, 1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(-1.0f, -1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, -1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(-1.0f, 1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, 1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(-1.0f, -1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, -1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)}, 
};

// create the vertex buffer
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(VERTEX) * 8;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

device->CreateBuffer(&bd, NULL, &pBuffer);

void* pVoid;    // the void pointer

pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the vertex buffer
memcpy(pVoid, OurVertices, sizeof(OurVertices));    // copy the vertices to the buffer
pBuffer->Unmap();

// create the index buffer out of DWORDs
DWORD OurIndices[] = 
{
    0, 1, 2,    // side 1
    2, 1, 3,
    4, 0, 6,    // side 2
    6, 0, 2,
    7, 5, 6,    // side 3
    6, 5, 4,
    3, 1, 7,    // side 4
    7, 1, 5,
    4, 5, 0,    // side 5
    0, 5, 1,
    3, 7, 2,    // side 6
    2, 7, 6,
};

// create the index buffer
// D3D10_BUFFER_DESC bd;    // redefinition
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(DWORD) * 36;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

device->CreateBuffer(&bd, NULL, &iBuffer);

// void* pVoid;    // redefinition

iBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the index buffer
memcpy(pVoid, OurIndices, sizeof(OurIndices));    // copy the indices to the buffer
iBuffer->Unmap();
}

Direct3D.h

#ifndef DIRECT3D_H
#define DIRECT3D_H

// global declarations
static ID3D10Device* device;
static ID3D10Buffer* pBuffer;
static ID3D10Buffer* iBuffer;    // the pointer to the index buffer
static ID3D10RenderTargetView* rtv;    // the pointer to the render target view
static ID3D10DepthStencilView* dsv;    // the pointer to the depth stencil view
static IDXGISwapChain* swapchain;    // the pointer to the swap chain class
static ID3D10Effect* pEffect;
static ID3D10EffectTechnique* pTechnique;
static ID3D10EffectPass* pPass;
static ID3D10InputLayout* pVertexLayout;
static ID3D10EffectMatrixVariable* pTransform;    // the pointer to the effect variable interface
static D3D10_PASS_DESC PassDesc;

// function prototypes
void initD3D(HWND hWnd);
void render_frame();
void init_pipeline();
void cleanD3D();
void Init();

#endif

cube.cpp

#include "cube.h"
#include "globals.h"
#include "Direct3D.h"

// include the Direct3D Library file
#pragma comment (lib, "d3d10.lib")
#pragma comment (lib, "d3dx10.lib")

Cube::Cube() : GameObject() 
{

}

Cube::~Cube() 
{
pBuffer->Release(); // why does this only work when put here? because it's    created here? I thnk so, why not iBuffer though?
}

void Cube::Draw()
{
render_frame();
}

void Cube::Init()
{
// create eight vertices to represent the corners of the cube
VERTEX OurVertices[] =
{
    {D3DXVECTOR3(-1.0f, 1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, 1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(-1.0f, -1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, -1.0f, -1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(-1.0f, 1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, 1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(-1.0f, -1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)},
    {D3DXVECTOR3(1.0f, -1.0f, 1.0f), D3DXCOLOR(1.0f, 0.0f, 0.0f, 1.0f)}, 
};

// create the vertex buffer
D3D10_BUFFER_DESC bd;
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(VERTEX) * 8;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

device->CreateBuffer(&bd, NULL, &pBuffer);

void* pVoid;    // the void pointer

pBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the vertex buffer
memcpy(pVoid, OurVertices, sizeof(OurVertices));    // copy the vertices to the buffer
pBuffer->Unmap();

// create the index buffer out of DWORDs
DWORD OurIndices[] = 
{
    0, 1, 2,    // side 1
    2, 1, 3,
    4, 0, 6,    // side 2
    6, 0, 2,
    7, 5, 6,    // side 3
    6, 5, 4,
    3, 1, 7,    // side 4
    7, 1, 5,
    4, 5, 0,    // side 5
    0, 5, 1,
    3, 7, 2,    // side 6
    2, 7, 6,
};

// create the index buffer
// D3D10_BUFFER_DESC bd;    // redefinition
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(DWORD) * 36;
bd.BindFlags = D3D10_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;

device->CreateBuffer(&bd, NULL, &iBuffer);

// void* pVoid;    // redefinition

iBuffer->Map(D3D10_MAP_WRITE_DISCARD, 0, &pVoid);    // map the index buffer
memcpy(pVoid, OurIndices, sizeof(OurIndices));    // copy the indices to the buffer
iBuffer->Unmap();
}

cube.h

#ifndef CUBE_H
#define CUBE_H

#include "gameObject.h"

class Cube : GameObject
{
private:
//VERTEX* OurVertices;
public:
Cube();
~Cube();
void Draw();
void Init();
};

#endif

so basically, if I call Init() from game.cpp, the code works fine, if I call cube->init(), just as this function is entered (not when the other one is left), the device pointer suddenly has an address of 0x00000000. Thanks in advance for any help you can give.

Both functions are identical - copy pasted.

share|improve this question
2  
You should remove render and cleanup code because it's not relevant to the question. Other code should also be removed, because if you have a null pointer at some line it makes no sense to look into the next lines for the bug, just truncate it from the first exception you get. –  Pablo Ariel Sep 24 '11 at 12:33
    
well I thought I should include it all because I have no idea what the problem is. –  Asher Einhorn Sep 26 '11 at 11:58
add comment

2 Answers 2

up vote 2 down vote accepted

At first glance, I would say it's because you have statics in your Direct3D.h header file.

static in a header file has the effect of creating a distinct copy per translation unit (i.e. in your case, one for game.cpp, one for cube.cpp), each of which is initialised to zero.

Instead, you should remove the static keyword to make them extern, add the definitions to a .cpp file, and initialise them properly.

share|improve this answer
    
I had no idea, thank you! –  Asher Einhorn Sep 26 '11 at 19:05
    
the trouble is, they're not really initialised. You pass the pointer to specialised methods and these initialise them, but if i make them extern as you say, i get unresolved external symbol errors - i'm assuming because the compiler can't find the definitions. –  Asher Einhorn Sep 27 '11 at 12:51
    
@SirYakalot: That would be correct. As I wrote, the definitions need to be in a .cpp file, although the declarations must be in the header file in order for them to be available to anyone who #includes it. This is so that the linker allocates space for one and only one instance of each of your variables. en.wikipedia.org/wiki/External_variable has an example of this in the "GlobalVariable" variable in its example. –  Kaz Dragon Sep 27 '11 at 13:28
add comment

But are you creating the cube instance somewhere? such as cube1 = new Cube() and there could be another device variable defined with the same name, such as a protected member of GameObject?

Try removing "static" from static ID3D10Device* device; and see if that fixes the problem. Not sure about this though

Like this:

void Initialise(HWND hWnd)
{   
    cube1 = new Cube();
    initD3D(hWnd);
    init_pipeline();
    test();
    cube1->Init();

// Init(); }

share|improve this answer
    
thanks, i'll give that a go. This really has me stumped. –  Asher Einhorn Sep 26 '11 at 9:58
    
nah, I just get linker errors. But yes, the cube is an object. –  Asher Einhorn Sep 26 '11 at 12:00
    
if you get linker problems from adding 'new', you don't have code to create the object. –  Jari Komppa Sep 26 '11 at 12:41
    
it's not from adding 'new', it's from removing 'static'. –  Asher Einhorn Sep 26 '11 at 12:58
    
I'm just not sure what's making the pointer null. –  Asher Einhorn Sep 26 '11 at 15:22
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.