using dlls *solved

Started by
8 comments, last by mystb 16 years ago
ive just started dividing my project into static libraries and dlls... im new to it im a bit unsure how one would go about when deciding what to put as a static library and what to put as an DLL... right now ive got it something like this... Static library: Application (windows window creatin, message handling etc...) Static library: Engine (3d engine specific stuff) Static library: Graphics API interfaces Dynamic library: Direct3D implementation (since i want to be able to easily change api) is this the way its meant to be used? im creating the libraries as described here http://msdn2.microsoft.com/en-us/library/ms235627(VS.80).aspx http://msdn2.microsoft.com/en-us/library/ms235636(VS.80).aspx the second thing is that the way its explained in the links above... i dont have any use of the "Graphics API" interfaces (the Direct3D implementation is based on those interfaces)... the reason i want to use these interfaces is soo that i can simply switch which dll to link to the project and the appropriate function will be loaded from the selected dll... and change api.. atleast thats the idea... just to make it clear.. what i want to achieve is a simple way to change from one graphics api to another... without having to change any(or much) code [Edited by - Dragon_Strike on April 2, 2008 9:24:08 AM]
Advertisement
well, you don't need any dll to do that (you'll need it if you don't want to recompile the main program).

What you really want is to add a layer between the graphics api and your application. When you want to change graphics api, you just need to redo the layer.

But if you're strugling with these concepts, if I were you, I wouldn't worry about things like this. Work your way out to make a game or two. Then you'll have enough knowledge to do this :)
ive already got a layer between them..

Game->Graphics API interface->API implementation

the thing is though i have to change all the "includes" and "new *Object*"... id liek ti to be a bit more dynamic...


lets say ive got

Graphics library:
RenderDevice.h

D3D10Device library:
D3D10RenderDevice.h

then in the demo source

#include "RenderDevice.h"
#include "D3D10RenderDevice.h"

class Demo1
{
public:
Demo1()
{
renderDevice = new D3D10RenderDevice;
}

RenderDevicePtr renderDevice_;
};

now if i wanted to change to an Opengl Renderdevice...u can see which changes i ahve to do...

Quote:
Work your way out to make a game or two


ive already done that... and i thought its about time i learn this stuff

EDIT:

now i think i get what u mean by a layer between the two... do u mean id create two Facades/unified interfaces... one for directx and one for opengl that manages the creating and use of all api specific stuff... and make the calls through this
it's really easy.

Create a .cpp/.h that delivers functionality to your app.(ex: graphics.cpp/.h)
This is generic (MyOwnInitGraphicsFunction)

you only include this .h in your game.

now create two more .h/.cpp files that work directly with directx (ex: d3graphics.cpp/.h)

now you should include d3graphics.h in graphics.cpp. in MyOwnInitGraphicsFunction you just call the directx init functions.

After that, create two more files(graphics.cpp/.h). But these ones call functions on GLgraphics.cpp/.h

This away, you provide a consistent function layer to your app. You can also make these .cpp reside in a dll, meaning that you only need to swap dlls to change rendering api.

Hope it helps :)

thx... soo basicly what i need to create is some kind of abstract factory...

ive got an implementation of the abstract factory pattern it looks something like this...

typedef AbstractFactory<mpl::vector<D3D10Texture, D3D10Buffer>, boost::variant<std::string, int>> GraphicsDevice;

shared_ptr<Texture> diffuse1 = GraphicsDevice->Register<Texture>("diffuse1", "filepath.tga", TEXTURE_2D );

which works fine... but my question is... how can i fool the "AbstractFactory" class that the template parameter "Texture" really should be "D3D10Texture"... is there any typedef trick or somehting i can use?

otherwise ill have to make a separate implementation... which wont be very flexible in adding new types...
Hi,

DLLs are just a tool. Partitioning code between EXE and DLL depends on your own needs. You want to be able to switch Graphic libraries, your approach is correct: the generic API in the EXE and one DLL per library (OpenGL, Direct3D, GDI, ...).

Another example of partitioning: I have written a forth virtual machine under Windows. As I did not want to fully recompile the interpreter each time I added commands, the main virtual machine was in the EXE and I created DLLs each time I added a group of commands using a standardized WordSet API.

Ragarding your second point:
The walkthrough is interesting to declare a class exported in a DLL. However, you can do much simpler: your DLL can export only one function which aim is to create an instance of your graphics API and return a pointer to the API.

DLL header
#include "Graphics_API.h"extern "C" __declspec(dllexport) Graphics_API* GetDirect3DImplementation(void);


DLL cpp
#include "DLL_header.h"#include "Direct3D_implementation.h"extern "C" __declspec(dllexport) Graphics_API* GetDirect3DImplementation(void){   return static_cast<Graphics_API*>(new Direct3D_implementation);}


This can be as simple as that (a simple improvement is to make sure that a loaded DLL returns only one instance of your Graphics library implementation).

Be aware that there are hidden snags when using DLLs. It is mandatory that the API have strictly the same version between the executable and DLLs. If the API is not of the same version, you will get hard untraceable bugs (even crashes). This means that any change in API structure will need you to recompile the EXE and all DLLs using that API.
You can also try to manage multiple API versions: it is harder to implement properly (see how Microsoft went with DirectX using COM).

Have fun.

Ghostly yours,
Red.
Ghostly yours,Red.
thx... but one question

that way i cant use generics since templates doesnt support polymorphism... which forces me to create function like "CreateTexture" etc... instead of Create<Texture> which is kinda ugly... any solution?
Hi,

It all depends on your design. Consider for a moment what is the realm of your graphics API:
- manage a display area
- manage offscreen textures for specialized rendering (plasma effects for example)
- display primitives
- convert loaded bitmap assets into texture objects
- manage rendering states
- compute picking rays and/or frustum corners

I also have written a few small games. To me asset loading is distinct from texture creation. The way I solved texture creation and management was very simple:
- I pass to the graphics API an interface to an asset loading class.
- When I request for a texture using an asset name to the graphics API, it checks wether it already has a handle corresponding to that asset. If it has, the existing handle is returned, else it calls the asset loading API to load the corresponding asset then create a texture and return the handle to that new texture.

IMHO, it is inevitable that the graphics API is of higher level that the underlying libraries (OpenGL or Direct3D or windows GDI).

To answer your question, I do not think you need to use generics for your texture management since texture creation is often strongly tied to the underlying library (compare OpenGL, DirectX and GDI when you need to store a bitmap for display). This is why I suggest to keep texture information internal to your graphics API and only provide handles to textures to all objects requesting the use of textures.

Hope that helps.

Ghostly yours,
Red.

PS: note that the element returned by the graphics API main not be limited to a handle. It can be a structure holding texture information (handle, size, ...)
Red.
Ghostly yours,Red.
thx for the tips...


im havin a little problem here... im trying to use runtime linkin...


Demo1.hpp
typedef graphics::IGraphicsDevice* (*GetGraphicsDevice)();	Demo1()	{		GetGraphicsDevice _GetGraphicsDeviceFunc = 0;		HINSTANCE hInstLibrary = LoadLibrary(TEXT("D3D10Device.dll"));		if (hInstLibrary)	    {		  _GetGraphicsDeviceFunc = (GetGraphicsDevice)GetProcAddress(hInstLibrary, "GetGraphicsDevice");		  if (_GetGraphicsDeviceFunc)			pGraphicsDevice.reset(_GetGraphicsDeviceFunc());					  FreeLibrary(hInstLibrary);		}		else		{			throw std::exception("Failed to load library");		}}


this part runs... but i dont think i get the correct function pointer... since as soon as i use pGraphicsDevice i get an acess violation error... whats wrong? namespaces doesnt matter right?


EDIT: id also like to note.. that it does work when i use the way described in the links in my first post... soo its nothing wrong behind the scenes

EDIT2: and how can it find "D3D10Device.dll"... i have the D3D10Device in the same solution, compiled, referenced and everything... but i cant find such a file in the file explorer... ? closest i get is "D3D10Device.dll.embed.manifest"

D3D10GraphicsDevice.hpp which is a part of the dll
#pragma once#include "D3D10RenderDevice.hpp"#include "D3D10Font.hpp"#include "GraphicsDevice.hpp"namespace drone{    namespace d3d10{extern "C" __declspec(dllexport) graphics::IGraphicsDevice* GetGraphicsDevice();class GraphicsDevice : public graphics::IGraphicsDevice{public:	void BindWindow(application::win32::WindowPtr window);	graphics::IRenderDevicePtr GetRenderDevice();	graphics::IFontPtr		  CreateFont(PCWSTR pFaceName, INT Height, UINT Width = 0, UINT Weight = FW_NORMAL, BOOL Italic = FALSE);private:	RenderDevicePtr pRenderDevice_;};typedef boost::shared_ptr<GraphicsDevice> GraphicsDevicePtr;	}}


D3D10GraphicsDevice.cpp
#include "D3D10GraphicsDevice.hpp"namespace drone{	namespace d3d10{extern "C" __declspec(dllexport) graphics::IGraphicsDevice* GetGraphicsDevice(){	return static_cast<graphics::IGraphicsDevice*>(new GraphicsDevice);}void GraphicsDevice::BindWindow(application::win32::WindowPtr window){	pRenderDevice_.reset(new RenderDevice(window));}graphics::IRenderDevicePtr GraphicsDevice::GetRenderDevice() { 	return pRenderDevice_; }graphics::IFontPtr GraphicsDevice::CreateFont(PCWSTR pFaceName, INT Height, UINT Width, UINT Weight, BOOL Italic){	return FontPtr(new Font(pRenderDevice_,				   Height, 				   Width, 				   Weight, 				   1, 				   Italic, 				   DEFAULT_CHARSET, 				   OUT_DEFAULT_PRECIS, 				   DEFAULT_QUALITY, 				   DEFAULT_PITCH | FF_DONTCARE, 				   pFaceName));}	}}				
in your first example... you don't want to free the library until the end of the application :)

This topic is closed to new replies.

Advertisement