Sign in to follow this  
falcon93

error LNK2001: unresolved external symbol

Recommended Posts

falcon93    121
Hi all!

I get some strange errors when I try to declare some methods as static. I've searched on google for it, but havn't managed to solve it. Here's the error messages:


[quote name="Visual Studio - Error Window - Error 1"]error LNK2001: unresolved external symbol "public: static struct IDirect3DDevice9 * Graphics::d3ddev" ([email="?d3ddev@Graphics@@2PAUIDirect3DDevice9@@A"]?d3ddev@Graphics@@2PAUIDirect3DDevice9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 2"]error LNK2001: unresolved external symbol "public: static struct IDirect3D9 * Graphics::d3d" ([email="?d3d@Graphics@@2PAUIDirect3D9@@A"]?d3d@Graphics@@2PAUIDirect3D9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 3"]error LNK2001: unresolved external symbol "public: static struct Graphics::CUSTOMVERTEX * Graphics::vertices" ([email="?vertices@Graphics@@2PAUCUSTOMVERTEX@1@A"]?vertices@Graphics@@2PAUCUSTOMVERTEX@1@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 4"]error LNK2001: unresolved external symbol "public: static struct IDirect3DVertexBuffer9 * Graphics::v_buffer" ([email="?v_buffer@Graphics@@2PAUIDirect3DVertexBuffer9@@A"]?v_buffer@Graphics@@2PAUIDirect3DVertexBuffer9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 5"]error LNK2001: unresolved external symbol "public: static struct _D3DSURFACE_DESC Graphics::surface" ([email="?surface@Graphics@@2U_D3DSURFACE_DESC@@A"]?surface@Graphics@@2U_D3DSURFACE_DESC@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 6"]error LNK2001: unresolved external symbol "public: static struct IDirect3DTexture9 * Graphics::texture" ([email="?texture@Graphics@@2PAUIDirect3DTexture9@@A"]?texture@Graphics@@2PAUIDirect3DTexture9@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 7"]error LNK2001: unresolved external symbol "public: static void * Graphics::pVoid" ([email="?pVoid@Graphics@@2PAXA"]?pVoid@Graphics@@2PAXA[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\Graphics.obj[/quote]

[quote name="Visual Studio - Error Window - Error 8"]error LNK1120: 7 unresolved externals C:\Users\Simon Blom\Desktop\AvoidBall\Debug\AvoidBall.exe[/quote]


GraphicsEngine.h
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9.h>


#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")


#pragma once


class GraphicsEngine
{

public:
static void Initialize(HWND hWnd);
static void InitGraphics(void);
static void Update(void);
static void Draw(void);

public:
static LPDIRECT3D9 d3d;
static LPDIRECT3DDEVICE9 d3ddev;
static LPDIRECT3DVERTEXBUFFER9 v_buffer;
static IDirect3DTexture9* texture;
static D3DSURFACE_DESC surface;
static VOID* pVoid;

public:
static struct CUSTOMVERTEX { float X, Y, Z, RHW; D3DCOLOR COLOR; float U, V; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
static CUSTOMVERTEX vertices[4];

};
[/source]


GraphicsEngine.cpp
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"


void GraphicsEngine::Initialize(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
}


void GraphicsEngine::InitGraphics(void)
{
D3DXCreateTextureFromFileEx(d3ddev, L"texture.jpg", 0, 0, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &texture);
texture->GetLevelDesc(0, &surface);

d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);

vertices[0].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].X = 100;
vertices[0].Y = 100;
vertices[0].Z = 0;
vertices[0].RHW = 1;
vertices[0].U = 0.0f;
vertices[0].V = 0.0f;

vertices[1].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].X = 100 + 25;
vertices[1].Y = 100;
vertices[1].Z = 0;
vertices[1].RHW = 1;
vertices[1].U = 1.0f;
vertices[1].V = 0.0f;

vertices[2].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].X = 100 + 25;
vertices[2].Y = 100 + 25;
vertices[2].Z = 0;
vertices[2].RHW = 1;
vertices[2].U = 1.0f;
vertices[2].V = 1.0f;

vertices[3].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].X = 100;
vertices[3].Y = 100 + 25;
vertices[3].Z = 0;
vertices[3].RHW = 1;
vertices[3].U = 0.0f;
vertices[3].V = 1.0f;
}


void GraphicsEngine::Update(void)
{
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}


void GraphicsEngine::Draw(void)
{
d3ddev->Clear(9, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
[/source]


Please help :(

Share this post


Link to post
Share on other sites
Wooh    1088
I'm a little bit confused by the error messages. In your code it it says GraphicsEngine but in the error messages they only say Graphics. Are you sure you use GraphicsEngine and not Graphics in other parts of your code.

Also, what is a static struct supposed to do? I don't think there is such a thing in C++.

Share this post


Link to post
Share on other sites
ArthY303    1153
Hello ...

Try this: before the function: void GraphicsEngine::Initialize(HWND hWnd), you need to define those static member variables

[code]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"

LPDIRECT3D9 GraphicsEngine :: d3d = NULL;
LPDIRECT3DDEVICE9 GraphicsEngine :: d3ddev = NULL;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine :: v_buffer = NULL;
IDirect3DTexture9* GraphicsEngine :: texture = NULL;
D3DSURFACE_DESC GraphicsEngine :: surface;
VOID* GraphicsEngine :: pVoid = NULL;

void GraphicsEngine::Initialize(HWND hWnd)
{
}
[/code]

Share this post


Link to post
Share on other sites
Promethium    580
When you declare class fields as static you will have to provide an actual instantiation. In your cpp file, add "[font=Consolas,]LPDIRECT3D9 [/font][font=Consolas,]GraphicsEngine::[/font][font=Consolas,]d3d = 0;" (0 because it is a pointer, use an appropriate default value) and so on for all your static fields.[/font]
[font=Consolas,]
[/font]
[font=Consolas,]Also, as Wooh points out, don't put static infront of your struct CUSTOMVERTEX { ... };[/font]
[font=Consolas,]
[/font]
[font=Consolas,]Lastly, put "#pragma once" at the very top of the .h file. It tells the compiler "only look at this file the first time you encounter it." It will make your compiles faster.[/font]
[font=Consolas,]
[/font]
[font=Consolas,]But you might want to reconsider your approach. Making every field and member of a class static is not really a good idea. It's (IMO) better to create a normal class and then have a single global instance. (Disregarding the whole using globals good/bad discussion for now.) [/font]
[font=Consolas,] [/font]
[font=Consolas,]
[/font]

Share this post


Link to post
Share on other sites
falcon93    121
Thanks very much for helping me :)


[quote name='Wooh' timestamp='1311152528' post='4837855']
I'm a little bit confused by the error messages. In your code it it says GraphicsEngine but in the error messages they only say Graphics. Are you sure you use GraphicsEngine and not Graphics in other parts of your code.

Also, what is a static struct supposed to do? I don't think there is such a thing in C++.
[/quote]

Yeah, the class was named Graphics before. It however seemed that Graphics was a reserved keyword and therefore I changed back to GraphicsEngine. I copied all errors before I changed back, thats why :wink:

Removed the static from the struct.




[quote name='ArthY303' timestamp='1311152882' post='4837856']
Hello ...

Try this: before the function: void GraphicsEngine::Initialize(HWND hWnd), you need to define those static member variables

[code]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"

LPDIRECT3D9 GraphicsEngine :: d3d = NULL;
LPDIRECT3DDEVICE9 GraphicsEngine :: d3ddev = NULL;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine :: v_buffer = NULL;
IDirect3DTexture9* GraphicsEngine :: texture = NULL;
D3DSURFACE_DESC GraphicsEngine :: surface;
VOID* GraphicsEngine :: pVoid = NULL;

void GraphicsEngine::Initialize(HWND hWnd)
{
}
[/code]
[/quote]

I've added the above declarations, and the errors has now lowered to an amount of 3 (see below) :D




[quote name='Promethium' timestamp='1311153208' post='4837859']
When you declare class fields as static you will have to provide an actual instantiation. In your cpp file, add "[font="Consolas,"]LPDIRECT3D9 [/font][font="Consolas,"]GraphicsEngine::[/font][font="Consolas,"]d3d = 0;" (0 because it is a pointer, use an appropriate default value) and so on for all your static fields.[/font]
[font="Consolas,"]
[/font]
[font="Consolas,"]Also, as Wooh points out, don't put static infront of your struct CUSTOMVERTEX { ... };[/font]
[font="Consolas,"]
[/font]
[font="Consolas,"]Lastly, put "#pragma once" at the very top of the .h file. It tells the compiler "only look at this file the first time you encounter it." It will make your compiles faster.[/font]
[font="Consolas,"]
[/font]
[font="Consolas,"]But you might want to reconsider your approach. Making every field and member of a class static is not really a good idea. It's (IMO) better to create a normal class and then have a single global instance. (Disregarding the whole using globals good/bad discussion for now.) [/font]
[/quote]

Ok, I've tried to declare them and setting them to both null and 0. It lowered my amount of errors, but there's still 3 errors left (se below). The static in front of the struct has also been removed.

Thank you very much for actually making me understand what "#pragma once" does, that line has always been strange to me, untill now :P

How would you advise me to do? Why I thought static methods would be good is becouse I can reach them even from the player-class and enemy-class (see image in my first post). How would you have done if you wanted to access the Draw method from classes that is "below" the GraphicsEnigne?


- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


So, here's my current code and errors:


GraphicsEngine.h:
[source lang="cpp"]
#pragma once


#include <d3d9.h>
#include <d3dx9.h>


#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")


class GraphicsEngine
{

public:
static void Initialize(HWND hWnd);
static void InitGraphics(void);
static void Update(void);
static void Draw(void);

public:
static LPDIRECT3D9 d3d;
static LPDIRECT3DDEVICE9 d3ddev;
static LPDIRECT3DVERTEXBUFFER9 v_buffer;
static IDirect3DTexture9* texture;
static D3DSURFACE_DESC surface;
static VOID* pVoid;

public:
struct CUSTOMVERTEX { float X, Y, Z, RHW; D3DCOLOR COLOR; float U, V; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
static CUSTOMVERTEX vertices[4];

};
[/source]


GraphicsEngine.cpp:
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"


LPDIRECT3D9 GraphicsEngine::d3d = 0;
LPDIRECT3DDEVICE9 GraphicsEngine::d3ddev = 0;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine::v_buffer = 0;
IDirect3DTexture9* GraphicsEngine::texture = 0;
D3DSURFACE_DESC surface;
VOID* GraphicsEngine::pVoid = 0;


void GraphicsEngine::Initialize(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
}


void GraphicsEngine::InitGraphics(void)
{
D3DXCreateTextureFromFileEx(d3ddev, L"texture.jpg", 0, 0, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &texture);
texture->GetLevelDesc(0, &surface);

d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);

vertices[0].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].X = 100;
vertices[0].Y = 100;
vertices[0].Z = 0;
vertices[0].RHW = 1;
vertices[0].U = 0.0f;
vertices[0].V = 0.0f;

vertices[1].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].X = 100 + 25;
vertices[1].Y = 100;
vertices[1].Z = 0;
vertices[1].RHW = 1;
vertices[1].U = 1.0f;
vertices[1].V = 0.0f;

vertices[2].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].X = 100 + 25;
vertices[2].Y = 100 + 25;
vertices[2].Z = 0;
vertices[2].RHW = 1;
vertices[2].U = 1.0f;
vertices[2].V = 1.0f;

vertices[3].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].X = 100;
vertices[3].Y = 100 + 25;
vertices[3].Z = 0;
vertices[3].RHW = 1;
vertices[3].U = 0.0f;
vertices[3].V = 1.0f;
}


void GraphicsEngine::Update(void)
{
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}


void GraphicsEngine::Draw(void)
{
d3ddev->Clear(9, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
[/source]


[quote name="Visual Studio - Error Window - Error 1"]
error LNK2001: unresolved external symbol "public: static struct GraphicsEngine::CUSTOMVERTEX * GraphicsEngine::vertices" ([email="?vertices@GraphicsEngine@@2PAUCUSTOMVERTEX@1@A"]?vertices@GraphicsEngine@@2PAUCUSTOMVERTEX@1@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\GraphicsEngine.obj
[/quote]

[quote name="Visual Studio - Error Window - Error 2"]
error LNK2001: unresolved external symbol "public: static struct _D3DSURFACE_DESC GraphicsEngine::surface" ([email="?surface@GraphicsEngine@@2U_D3DSURFACE_DESC@@A"]?surface@GraphicsEngine@@2U_D3DSURFACE_DESC@@A[/email]) C:\Users\Simon Blom\Desktop\AvoidBall\AvoidBall\GraphicsEngine.obj
[/quote]
Thats strange as I can't initialize the surface to either 0 or null :/



[quote name="Visual Studio - Error Window - Error 3"]
error LNK1120: 2 unresolved externals C:\Users\Simon Blom\Desktop\AvoidBall\Debug\AvoidBall.exe
[/quote]

Share this post


Link to post
Share on other sites
ArthY303    1153
Hi,

[code]

//You have to specify to which class surface belongs (i.e GraphicsEngine), you forgot to put that in your code.
D3DSURFACE_DESC GraphicsEngine :: surface;

// Put this line with the rest of the static members in your cpp file
CUSTOMVERTEX GraphicsEngine :: vertices[4];
[/code]

This will solve your errors.

Share this post


Link to post
Share on other sites
falcon93    121
[code]
LPDIRECT3D9 GraphicsEngine::d3d = 0;
LPDIRECT3DDEVICE9 GraphicsEngine::d3ddev = 0;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine::v_buffer = 0;
IDirect3DTexture9* GraphicsEngine::texture = 0;
D3DSURFACE_DESC GraphicsEngine::surface = 0;
VOID* GraphicsEngine::pVoid = 0;
GraphicsEngine::CUSTOMVERTEX GraphicsEngine::vertices[4] = 0;
[/code]

I've added that now, but i still can't set the surface to 0 or null, and neither can I set the vertices[4] to 0 or null? :(

Share this post


Link to post
Share on other sites
falcon93    121
[code]
LPDIRECT3D9 GraphicsEngine::d3d = 0;
LPDIRECT3DDEVICE9 GraphicsEngine::d3ddev = 0;
LPDIRECT3DVERTEXBUFFER9 GraphicsEngine::v_buffer = 0;
IDirect3DTexture9* GraphicsEngine::texture = 0;
D3DSURFACE_DESC GraphicsEngine::surface;
VOID* GraphicsEngine::pVoid = 0;
GraphicsEngine::CUSTOMVERTEX GraphicsEngine::vertices[4];
[/code]

I made it like this, and now it works. I'll drop a reply when I've done some cleanup in GraphicsEngine, but now it works to build atleast, and I even get no warnings. Thanks :)

Share this post


Link to post
Share on other sites
rip-off    10976
It appears you are writing a namespace, not a class.

[quote]
Why I thought static methods would be good is becouse I can reach them even from the player-class and enemy-class (see image in my first post). How would you have done if you wanted to access the Draw method from classes that is "below" the GraphicsEnigne?
[/quote]
For complex games, objects do not render themselves. But that aside, a simple way is the following:
[code]
void Player::Draw(GraphicsEngine &graphics) const
{
// Using "this" pointer for clarity
graphics.drawSprite(this->position, this->texture, /* ... */);
}
[/code]
Whatever you end up doing, you should almost certainly not be exposing all those variables as public.

Be aware that using preprocessor constants inside a class doesn't have any significance, as the preprocessor does not understand or respect C++ scoping rules. Try making it a const <type> (DWORD?) instead.

Share this post


Link to post
Share on other sites
falcon93    121
[quote name='rip-off' timestamp='1311173493' post='4837984']
It appears you are writing a namespace, not a class.

[quote]
Why I thought static methods would be good is becouse I can reach them even from the player-class and enemy-class (see image in my first post). How would you have done if you wanted to access the Draw method from classes that is "below" the GraphicsEnigne?
[/quote]
For complex games, objects do not render themselves. But that aside, a simple way is the following:
[code]
void Player::Draw(GraphicsEngine &graphics) const
{
// Using "this" pointer for clarity
graphics.drawSprite(this->position, this->texture, /* ... */);
}
[/code]
Whatever you end up doing, you should almost certainly not be exposing all those variables as public.

Be aware that using preprocessor constants inside a class doesn't have any significance, as the preprocessor does not understand or respect C++ scoping rules. Try making it a const <type> (DWORD?) instead.
[/quote]



Namespace? Whats the difference between a namespace and a class?

My plan was that all game objects that should be drawn should call on the GraphicEngines Draw method. However, if the Draw method wouldn't be static, I would have been forced to send references to it deep into sub classes. Therefore I thought that if the Draw method was static, I could reach it everywere in my game. And all variables that is used in a static method must also be static, right?

Then 3 small questions showed up:

1. Don't I need to send a whole vertex array as a parameter into my method?
2. Why is it a '&' infront of the "graphics" object? I guess that it's some kind of pointer, but how did you know that you should use it?
3. Could you please explain that "const" statement? I've actually never used it :/

Thanks very much for helping :)

Share this post


Link to post
Share on other sites
rip-off    10976
[quote]
Namespace? Whats the difference between a namespace and a class?
[/quote]
A namespace is a space for names =]. That is, the identifier "string" in namespace std is different from the namespace "falcon". In this way you can write any class names you want, provided you keep your namespaces separate from any libraries you are using.

Large programs might use namespaces to delimit module boundaries, or simply to separate all "our" code from "outside" code (in libraries). Small programs are often written in the default, global namespace.

A class is a blueprint for creating objects. If you are never going to create objects, then it doesn't make sense to pretend you are writing a class.
[quote]
My plan was that all game objects that should be drawn should call on the GraphicEngines Draw method.
[/quote]
Fair enough.
[quote]
However, if the Draw method wouldn't be static, I would have been forced to send references to it deep into sub classes.
[/quote]
Yes. I think you'll probably find it isn't all that deep, though!
[quote]
Therefore I thought that if the Draw method was static, I could reach it everywere in my game.
[/quote]
While true, it doesn't make it a good idea. When I was starting out, I used to write code like this. Eventually my program was this big mass of spaghetti where code from anywhere could make calls into completely unrelated subsystems. I later realised that this "design" is almost indistinguishable from the absence of design.

If you want to write code that is easy to read and maintain, you absolutely do not want to be able to reach across into unrelated modules like that. It takes some discipline, but you should be able to minimise the number of areas of the code that actually need to touch the GraphicsEngine. You'll probably find it isn't all that many places, once it has been factored a little better.

This often involves inverting control somewhere. So (for example), instead of your player object drawing the HUD (which is usually simple because it has access to its own health, ammo, etc), you might have a HUD object which handles this.

This is maybe a poor example, because the player in this case is drawing themselves, but it is an example of how one might approach this.
[quote]
And all variables that is used in a static method must also be static, right?
[/quote]
You cannot access instance member variables in a static method, unless you happen to have an instance object.

[quote]
1. Don't I need to send a whole vertex array as a parameter into my method?
[/quote]
Perhaps. Depends on the nature of the game. It would be nice if the client (e.g. the Player class) doesn't need to talk about graphics in such low level detail. It should be able to say "I want this drawn" and let the GraphicsEngine figure out how to get that on the screen. Hence my "drawSprite" member function.

[quote]
2. Why is it a '&' infront of the "graphics" object? I guess that it's some kind of pointer, but how did you know that you should use it?
[/quote]
That is C++ syntax for a "reference". They are a (better) alternative to pointers for most common uses. They cannot be null and cannot be reseated (something akin to pointing to a new object). They express the idea "here is an object that already exists". A pointer could be NULL, could be pointing to one object, could point to an array. You cannot tell

[quote]
3. Could you please explain that "const" statement? I've actually never used it :/
[/quote]
It marks the member function as "const". That is, the Player object is considered "const" for the duration of this method. This means that you cannot change the values of member variables.

This is an aspect of "const correctness". I think I've put enough on your plate for the moment, you might want to research that later!

Share this post


Link to post
Share on other sites
falcon93    121
It looks like I have very, very much more to learn :)

Well, I've read your reply and decided to do it in the more "correct" way, which means accessing the Draw method from references sent to all classes that will need to call for the Draw method.

However, now I have a new problem. I've done a few changes to my GraphicsEngine as I want it to support drawing many textures at the same time. Now I call the Draw methods twise with different data, but the textures is flickering, like they are drawn once per two loops. I've pasted my code from the GraphicsEngine below:


GraphicsEngine.h
[source lang="cpp"]
#pragma once


#include <d3d9.h>
#include <d3dx9.h>


#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")


class GraphicsEngine
{

public:
GraphicsEngine(HWND hWnd);
~GraphicsEngine(void);
void Update(void);
void Draw(LPCWSTR texture_path, float x, float y);

private:
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
LPDIRECT3DVERTEXBUFFER9 v_buffer;
D3DPRESENT_PARAMETERS d3dpp;
VOID* pVoid;
IDirect3DTexture9* texture;
D3DSURFACE_DESC surface;

private:
struct CUSTOMVERTEX { float X, Y, Z, RHW; D3DCOLOR COLOR; float U, V; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
CUSTOMVERTEX vertices[4];

};
[/source]



GraphicsEngine.cpp
[source lang="cpp"]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"


GraphicsEngine::GraphicsEngine(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);

d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);
}


GraphicsEngine::~GraphicsEngine(void)
{
}


void GraphicsEngine::Update(void)
{
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();
}


void GraphicsEngine::Draw(LPCWSTR texture_path, float x, float y)
{
D3DXCreateTextureFromFileEx(d3ddev, texture_path, 0, 0, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &texture);
texture->GetLevelDesc(0, &surface);

vertices[0].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].X = x;
vertices[0].Y = y;
vertices[0].Z = 0;
vertices[0].RHW = 1;
vertices[0].U = 0.0f;
vertices[0].V = 0.0f;

vertices[1].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].X = x + surface.Width;
vertices[1].Y = y;
vertices[1].Z = 0;
vertices[1].RHW = 1;
vertices[1].U = 1.0f;
vertices[1].V = 0.0f;

vertices[2].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].X = x + surface.Width;
vertices[2].Y = y + surface.Height;
vertices[2].Z = 0;
vertices[2].RHW = 1;
vertices[2].U = 1.0f;
vertices[2].V = 1.0f;

vertices[3].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].X = x;
vertices[3].Y = y + surface.Height;
vertices[3].Z = 0;
vertices[3].RHW = 1;
vertices[3].U = 0.0f;
vertices[3].V = 1.0f;

d3ddev->Clear(9, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
[/source]


And here's main.cpp
[source lang="cpp"]
#include <Windows.h>
#include "Main.h"
#include "GraphicsEngine.h"


LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY: PostQuitMessage(0); return 0;
}

return DefWindowProc(hWnd, message, wParam, lParam);
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));

wc.cbSize = sizeof(WNDCLASSEX);
wc.hInstance = hInstance;
wc.lpfnWndProc = WindowProc;
wc.lpszClassName = L"AvoidBallClass";
wc.style = CS_VREDRAW | CS_HREDRAW;

RegisterClassEx(&wc);

HWND hWnd;
hWnd = CreateWindowEx(NULL, L"AvoidBallClass", L"AvoidBall", WS_OVERLAPPED, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);

MSG msg;

GraphicsEngine* graphics = new GraphicsEngine(hWnd);

while (true)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

graphics->Update();
graphics->Draw(L"texture.jpg", 100, 100);
graphics->Update();
graphics->Draw(L"texture.jpg", 400, 400);
}

// TODO: Clean up resource.

return msg.wParam;
}
[/source]



What am I doing wrong? :(

Share this post


Link to post
Share on other sites
rip-off    10976
Every call to Draw() clears and updates the screen, besides doing a fantastic level of work including loading the texture from a file! The update makes no sense, as it copies the data to the vertex buffer *after* you've asked Direct3D to render stuff - it is never in sync with the values passed in to Draw().

The draw method should not load files, nor should it clear the screen or present it.Perhaps add a "begin" and "end" method to the graphics engine, which WinMain() would call. To avoid loading files at runtime, add a "texture" class that handles a texture in memory. A player object might have a texture which it can pass to the renderer.

A simple implementation of the draw function would set the vertices, copy them to the vertex buffer and submit them to Direct3D.

In the end, your loop should look something like this:
[code]
// Don't dynamically allocate unless necessary!
GraphicsEngine graphics(hWnd);

Texture texture(L"texture.jpg");

while (true)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}

graphics.Begin();
graphics.Draw(texture, 100, 100);
graphics.Draw(texture, 400, 400);
graphics.End();
}
[/code]

Share this post


Link to post
Share on other sites
falcon93    121
I've done some cleanup in my GraphicsEngine.cpp, and added Begin() and End() methods. I've also created a Sprite class that I want to send into the GraphicsEngine and get all info from. I don't know where the "vertex buffer copy code" should be though. Below is my current code:

GraphicsEngine.h
[source lang="cpp]
#pragma once


#include <d3d9.h>
#include <d3dx9.h>
#include "Sprite.h"


#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")


class GraphicsEngine
{

public:
GraphicsEngine(HWND hWnd);
~GraphicsEngine(void);
void Begin(void);
void Draw(Sprite sprite);
void End(void);

public:
LPDIRECT3DDEVICE9 d3ddev;

private:
LPDIRECT3D9 d3d;
LPDIRECT3DVERTEXBUFFER9 v_buffer;
D3DPRESENT_PARAMETERS d3dpp;
IDirect3DTexture9* texture;
D3DSURFACE_DESC surface;
VOID* pVoid;

private:
struct CUSTOMVERTEX { float X, Y, Z, RHW; D3DCOLOR COLOR; float U, V; };
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1)
CUSTOMVERTEX vertices[4];

};
[/source]


GraphicsEngine.cpp
[source lang="cpp]
#include <d3d9.h>
#include <d3dx9tex.h>
#include "GraphicsEngine.h"
#include "Main.h"
#include "Sprite.h"


GraphicsEngine::GraphicsEngine(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);

ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;

d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);

d3ddev->CreateVertexBuffer(4*sizeof(CUSTOMVERTEX), 0, CUSTOMFVF, D3DPOOL_MANAGED, &v_buffer, NULL);
}


GraphicsEngine::~GraphicsEngine(void)
{
}


void GraphicsEngine::Begin(void)
{
d3ddev->Clear(9, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX));
}


void GraphicsEngine::Draw(Sprite sprite)
{
vertices[0].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[0].X = sprite.x;
vertices[0].Y = sprite.y;
vertices[0].Z = 0;
vertices[0].RHW = 1;
vertices[0].U = 0.0f;
vertices[0].V = 0.0f;

vertices[1].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[1].X = sprite.x + sprite.width;
vertices[1].Y = sprite.y;
vertices[1].Z = 0;
vertices[1].RHW = 1;
vertices[1].U = 1.0f;
vertices[1].V = 0.0f;

vertices[2].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[2].X = sprite.x + sprite.width;
vertices[2].Y = sprite.y + sprite.height;
vertices[2].Z = 0;
vertices[2].RHW = 1;
vertices[2].U = 1.0f;
vertices[2].V = 1.0f;

vertices[3].COLOR = D3DCOLOR_ARGB(255, 255, 255, 255);
vertices[3].X = sprite.x;
vertices[3].Y = sprite.y + sprite.height;
vertices[3].Z = 0;
vertices[3].RHW = 1;
vertices[3].U = 0.0f;
vertices[3].V = 1.0f;

v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, vertices, sizeof(vertices));
v_buffer->Unlock();

d3ddev->SetTexture(0, texture);
d3ddev->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
}


void GraphicsEngine::End()
{
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
[/source]


Sprite.h
[source lang="cpp]
#pragma once


#include <d3dx9tex.h>
#include "GraphicsEngine.h"


class Sprite
{

public:
Sprite(GraphicsEngine graphics, LPCWSTR texture_path, float x, float y, float width, float height);
~Sprite(void);

private:
IDirect3DTexture9* texture;
D3DSURFACE_DESC surface;

public:
float x;
float y;
float width;
float height;

};
[/source]


Sprite.cpp
[source lang="cpp]
#include "Sprite.h"
#include "GraphicsEngine.h"


Sprite::Sprite(GraphicsEngine graphics, LPCWSTR texture_path, float x, float y, float width, float height)
{
D3DXCreateTextureFromFileEx(graphics.d3ddev, texture_path, 0, 0, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, D3DX_FILTER_NONE, D3DX_FILTER_NONE, 0, NULL, NULL, &texture);

this->x = x;
this->y = y;
this->width = width;
this->height = height;
}


Sprite::~Sprite(void)
{
}
[/source]



From this I get the 4 following errors:

[quote name="Visual Studio - Error Window - Error 1"]
error C2061: syntax error : identifier 'Sprite' c:\users\simon blom\desktop\avoidball\avoidball\graphicsengine.h
[/quote]

[quote name="Visual Studio - Error Window - Error 2"]
error C2061: syntax error : identifier 'GraphicsEngine' c:\users\simon blom\desktop\avoidball\avoidball\sprite.h
[/quote]

[quote name="Visual Studio - Error Window - Error 3"]
error C2061: syntax error : identifier 'GraphicsEngine' c:\users\simon blom\desktop\avoidball\avoidball\sprite.h
[/quote]

[quote name="Visual Studio - Error Window - Error 4"]
IntelliSense: identifier "Sprite" is undefined c:\users\simon blom\desktop\avoidball\avoidball\graphicsengine.h
[/quote]


What am I doing wrong? :(

Share this post


Link to post
Share on other sites
Wooh    1088
You have a circular dependency. Sprite.h includes GraphicsEngine.h, and GraphicsEngine.h includes Sprite.h. That will not work. You can solve this by using forward declaration. For that to work you can't pass GraphicsEngine and Sprite by value as you do now.

Share this post


Link to post
Share on other sites
SiS-Shadowman    359
I'll explain the last post a bit:

The compiler translates each cpp file, and when looking at Sprite.cpp, it couldn't find Sprite because it first included Sprite.h, then GraphicsEngine.h, then Sprite.h again, HOWEVER there's a pragma once, thus it skips the second inclusion and tries to make sense of GraphicsEngine.h. The problem is that the Sprite class is NOT known at that point (remember that you included GraphicsEngine.h BEFORE the compiler actually knew the Sprite class).




You can solve this by forward declaring either one or (sometimes better) both types. Simply put "class GraphicsEngine" right before class Sprite { .... } and/or the other way around. As long as you don't actually USE the type (ie. access methods, pass it by value) from within the header, you are fine.

*edit*

Actually, the preprocessor pastes everything into one big "file" and then the compiler kicks in, however the order in which the compiler finds those types in the big file is the same as described above.

Share this post


Link to post
Share on other sites
falcon93    121
I'm not sure I understood the "forward" tecnique... Could you please post a small example? [img]http://public.gamedev.net/public/style_emoticons/default/unsure.gif[/img]

Share this post


Link to post
Share on other sites
SiS-Shadowman    359
[quote name='falcon93' timestamp='1311266033' post='4838505']
I'm not sure I understood the "forward" tecnique... Could you please post a small example? [img]http://public.gamedev.net/public/style_emoticons/default/unsure.gif[/img]
[/quote]

Sure thing:

Sprite.h:
[source]
#pragma once

// includes

class GraphicsEngine;
class Sprite
{
....public:

Sprite(GraphicsEngine& engine);

private:

GraphicsEngine& m_engine;
};
[/source]

Sprite.cpp
[source]
#include "Sprite.h"
#include "GraphicsEngine.h"
[/source]

The important point is that you cannot use/pass a forward declared type by value, ie "GraphicsEngine engine", but have to use/pass it by reference and/or pointer (GraphicsEngine& engine OR GraphicsEngine* engine): The reason behind this is that the compiler is required to know the size of the object to pass, in order to pass it by value (or use it as a member in a class), which it cannot on forward delcared types. Using references/pointers requires NO knowledge of the underlying type. But note that calling methods on that type or accessing members requires knowledge of the type, hence you are forced to place all code that accesses GraphicsEngine inside Sprite.cpp (and vice verca for GraphicsEngine.cpp if you forward declare Sprite as well).

*edit*

Please note that it also makes sense to pass the engine by reference: You don't want to copy it, but pass a reference TO the SAME object to all sprites, so those sprites can access the shared state of that single engine. Creating a copy of an engine would be a hard thing to implement, since you have to decide whether both instances access & render to the same window, etc... It is easier to forbid copying an engine alltogether by either inheriting from [url="http://www.boost.org/doc/libs/1_47_0/boost/noncopyable.hpp"]boost::noncopyable[/url] or by explicitly declaring the copy constructor private:

[source]

class CannotBeCopied

{

public:

...

private:

CannotBeCopied(const CannotBeCopied&);

};

[/source]

Share this post


Link to post
Share on other sites
falcon93    121
[code]

public:
Sprite(GraphicsEngine graphics, LPCWSTR texture_path, float x, float y, float width, float height);
~Sprite(void);
[/code]


I'm sending a reference from the GraphicsEngine into the Sprite here, right? But then I have to include the GraphicsEngine header file? Or?

Share this post


Link to post
Share on other sites
SiS-Shadowman    359
[quote name='falcon93' timestamp='1311268884' post='4838532']
[code]

public:
Sprite(GraphicsEngine graphics, LPCWSTR texture_path, float x, float y, float width, float height);
~Sprite(void);
[/code]


I'm sending a reference from the GraphicsEngine into the Sprite here, right? But then I have to include the GraphicsEngine header file? Or?
[/quote]
No you are not. You are passing graphics engine by value. In this case you would have to include GraphicsEngine.h in Sprite.h, but this will not solve the problem due to a circular dependency. Instead you should try what I write above, ie. "GraphicsEngine& engine" for the constructor and also storing a reference to the engine: "GraphicsEngine& m_engine;".


Share this post


Link to post
Share on other sites
falcon93    121
Won't that create a[i] new [/i]object of the GraphicsEngine? I'm not sure what the & does, but how can the reference know that m_engine actually is graphics_engine?

Share this post


Link to post
Share on other sites
Wooh    1088
The & here says it is a reference. A reference is similar to a pointer, so no copy is made. If you pass by value a copy is made.

Share this post


Link to post
Share on other sites
SiS-Shadowman    359
[quote name='falcon93' timestamp='1311271445' post='4838551']
Won't that create a[i] new [/i]object of the GraphicsEngine? I'm not sure what the & does, but how can the reference know that m_engine actually is graphics_engine?
[/quote]

You seem to be confused about what references are:


When you use & in conjunction with a type, you create a reference which does not create a new object. Instead a reference always points to an already existing object. Whereas a value always copies the existing object, thus creating yet another instance:


[source]


GraphicsEngine engine1; //< Now one graphics engine exists

GraphicsEngine engine2 = engine; //< A SECOND engine has been created by copying it from the first

GraphicsEngine& engine1_too = engine; //< this is the SAME as engine

[/source]

The same applies to function & method parameters: If you place a & after the type, then you are passing by reference, if you ommit it (and don't place a *) then you are passing by value.

Share this post


Link to post
Share on other sites
falcon93    121
So, check if this is correct, if it is, I think I've understood it [img]http://public.gamedev.net/public/style_emoticons/default/wink.gif[/img]



In Main.cpp
[code]

GraphicsEngine* graphics = new GraphicsEngine(); // This will create a new object of my GraphicsEngine.

Player* player; // I create my sprite object in the Player class constructor, just to simulate the situation in my game. The Sprite requies variables from GraphicsEngine, therefore:

player = new Player(graphics); // I send a reference. Not a new object or "copy"?

[/code]




In the Player constructor
[code]

Player::Player(GraphicsEngine& graphics) // I can use/write GraphicsEngine + & without having to include the .h file?
{
Sprite sprite = new Sprite(graphics); // Sends a reference to the sprite object
}

[/code]



In the Sprite constructor
Sprite::Sprite(GraphicsEngine& graphics) // I can use/write GraphicsEngine + & without having to include the .h file?
{
D3DXCreateTextureFromFileEx(graphics.d3ddev, .....);
}



Does this seems correct? Please tell me if anything is wrong, I would really like to learn this [img]http://public.gamedev.net/public/style_emoticons/default/smile.gif[/img]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this