org.lwjgl.d3d Progress / Thoughts

Started by gaarazero, March 13, 2008, 18:07:42

Previous topic - Next topic

gaarazero

I'll be posting any updates on org.lwjgl.d3d here.

Right now I have it building into a separate dll and jar, lwjgl-d3d.dll and lwjgl-d3d.jar respectively.  It also only builds for Windows.

Since Direct3D is written in an object-oriented way, wrapping it in Java is quite straightforward.  But, little things like capitalized method names and having an 'I' in front of the object names makes it quite tricky.  I think a one-to-one mapping would be the best and most simple way to do it, but I would also really like to adhere to the Java standards.  All this means is that instead of using IDirect3DDevice9 dev; it's now Direct3DDevice9 dev;, and instead of dev.BeginScene(); it's now dev.beginScene();.

Another change is that for many of the 'create' functions, you have to pass in a pointer to the object you want to create.  That's not how things are done in Java Land.  For these methods, I am planing on returning the object created and throwing an exception if it doesn't work; you don't have to use try and catch specifically, unless you really want to.  This is much more Java friendly.  I plan on still returning the HRESULTs from the other method calls.  Throwing exceptions would be more Java-esk, but most of the time you don't need to check the result.

I welcome any questions or comments.

-gz
JNewton 0.8 - Newton Dynamics wrapper for Java!
org.lwjgl.d3d - Currently Working On

Matzon

Quote from: gaarazero on March 13, 2008, 18:07:42
Right now I have it building into a separate dll and jar, lwjgl-d3d.dll and lwjgl-d3d.jar respectively.  It also only builds for Windows.
I'm sure that noone expects otherwise :) - tho I'd love to see it running under wine.

Quote from: gaarazero on March 13, 2008, 18:07:42
Since Direct3D is written in an object-oriented way, wrapping it in Java is quite straightforward.  But, little things like capitalized method names and having an 'I' in front of the object names makes it quite tricky.  I think a one-to-one mapping would be the best and most simple way to do it, but I would also really like to adhere to the Java standards.  All this means is that instead of using IDirect3DDevice9 dev; it's now Direct3DDevice9 dev;, and instead of dev.BeginScene(); it's now dev.beginScene();.
well, this is a bit of a "problem". from my point of view, it depends on how well it maps. one of the reasons that we chose the naming and static convention that we did for lwjgl, was that using import static would make a lot of the code "just" work from C/C++. By changing the names one has to refactor some code to make it work. Typically, however, this isn't a really big issue.

Quote from: gaarazero on March 13, 2008, 18:07:42
Another change is that for many of the 'create' functions, you have to pass in a pointer to the object you want to create.  That's not how things are done in Java Land.  For these methods, I am planing on returning the object created and throwing an exception if it doesn't work; you don't have to use try and catch specifically, unless you really want to.  This is much more Java friendly.  I plan on still returning the HRESULTs from the other method calls.  Throwing exceptions would be more Java-esk, but most of the time you don't need to check the result.
fair enough. The dx api, is really a bit ugly IMO.

Thanks for the update - do let us know if you have something ready for pre-pre-alpha :)

princec

I'd map the names directly, capitals and all, so C++ code looks very similar, if I were you.

Cas :)

ndhb

I too would keep the mapping as close to 1:1 as possible. This makes a transition easier and if people want Java style identifiers they can always just write their own wrappers on top of your work.

kappa

I prefer that slight changes be made to the names, as done above, since d3d is pretty ugly.
Although it will look slightly different from C/C++ d3d code, it will make the overall code look much cleaner and nicer.
Which will probably be a plus in attracting C/C++ d3d dev's since they will see how nice the code looks compared to what they are using.

VeAr

I also prefer Java style naming. I would not want my eyes hurt when looking at Java code that doesnt look like Java code.

princec

It's not a Java API though... so it shouldn't follow the Java naming conventions.

Cas :)

Fool Running

I think it would be better to keep the names as they are in DirectX (although I like the idea of returning an object and throwing an exception if something goes wrong).
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

princec

Does seem like a good candidate for an exception but... the original API returns HRESULTS... so that what this one should do. Anyone wanting Exceptions should wrap the library.

Cas :)

gaarazero

Thanks for all the input!

Quote from: Matzon on March 13, 2008, 20:26:03
I'm sure that noone expects otherwise :) - tho I'd love to see it running under wine.
I'll look into that, because it would be crazy :P.  But much later.

Quote from: Matzon on March 13, 2008, 20:26:03
well, this is a bit of a "problem". from my point of view, it depends on how well it maps. one of the reasons that we chose the naming and static convention that we did for lwjgl, was that using import static would make a lot of the code "just" work from C/C++. By changing the names one has to refactor some code to make it work. Typically, however, this isn't a really big issue.
Users would still have to refactor their C/C++ D3D code any way since there are multiple ways to program.  You can use
IDirect3DDevice9* dev;
PDIRECT3DDEVICE9 pdev;
LPDIRECT3DDEVICE9 lpdev;

(all three mean the same thing).

Then call methods via the C++ way
dev->BeginScene();
or the C way
IDirect3DDevice9_BeginScene( dev );


OpenGL is a C API anyway, so it's all functional programming, which Java can do.  Also, all the method names start with lowercase 'gl'.  You guys had it easy  ;).

Another thing is that if there is an 'I' in front of a class, it denotes an interface, even in C++.  Keeping it IDirect3DDevice9 in Java may confuse some newcomers.  But, after typing this and remembering that D3D is an interface for the graphics card, it makes sense to keep the 'I', kinda.

Quote from: Matzon on March 13, 2008, 20:26:03
fair enough. The dx api, is really a bit ugly IMO.
I agree.

Quote from: ndhb on March 14, 2008, 12:58:35
I too would keep the mapping as close to 1:1 as possible. This makes a transition easier and if people want Java style identifiers they can always just write their own wrappers on top of your work.
I'm pretty sure people wont get confused if their method names were lowercased.

I guess the best way to do it would be to have as little refactoring as possible.  But, refactoring will have to take place no matter what.

I'm really torn between keeping it 1:1 or making it more Java friendly.  There are positives and negatives to both.  I'm leaning more to make it Java friendly.  I think users of D3D would appreciate it.

A solution I came up with was to provide both capitalized and lowercase method names and both 'create' method types, returning an HRESULT or an object.  Hell, why not include the C wrapper as well :P.  I'm only kidding... unless it's a good idea.

-gz
JNewton 0.8 - Newton Dynamics wrapper for Java!
org.lwjgl.d3d - Currently Working On

gaarazero

To give an example of what I'm talking about when I say 'create' methods, here is the original C/C++ code:
IDirect3DDevice9* dev; //assume created successfully
D3DPRESENT_PARAMETERS params; //assume created
IDirect3DSwapChain9* swapchain = NULL;

HRESULT r = dev->CreateAdditionalSwapChain( &params, &swapchain );
if( r != D3D_OK) {
... //fail code
}


The Java equivalent would be:
IDirect3DDevice9 dev; //assume created successfully
D3DPersentParameters params; //assume created
IDirect3DSwapChain9 swapchain = new IDirect3DSwapChain9();

int r = dev.CreateAdditionalSwapChain( params, swapchain );
if( r != Constants.D3D_OK ) {
...//fail code
}


That looks almost counter productive.  You create a new swap chain, then call a method that says "create a new swap chain".  The refactor I propose would look like:
IDirect3DDevice9 dev; //assume created successfully
D3DPersentParameters params; //assume created

IDirect3DSwapChain9 swapchain = dev.CreateAdditionalSwapChain( params );
if( swapchain == null ) {
...//fail code
}


There is only one or two methods that I can think of were the HRESULT is actually useful; TestCooperativeLevel() is the first one that comes to mind.  Also, most of the time it doesn't really matter what is returned, as long as its D3D_OK.  Additionally, with the first Java example, there is still a SwapChain object that can be used, unless you set it to null in the fail code section, but then why did you need to create it in the first place.  Returning them is useful, but going out of the way to accommodate them for the sake of 1:1-ness is crazy.

-gz
JNewton 0.8 - Newton Dynamics wrapper for Java!
org.lwjgl.d3d - Currently Working On

elias

Quote from: gaarazero on March 23, 2008, 02:43:14
I'm really torn between keeping it 1:1 or making it more Java friendly.  There are positives and negatives to both.  I'm leaning more to make it Java friendly.  I think users of D3D would appreciate it.

I've never really used d3d, so I can only make general comments from experience with the rest of lwjgl.

From the frontpage of lwjgl.org: "LWJGL is not meant to make writing games particularly easy; it is primarily an enabling technology which allows developers to get at resources that are simply otherwise unavailable or poorly implemented on the existing Java platform." LWJGL is about enabling otherwise hard or impossible to access functionality, which means that your job is to make it possible to access d3d from java and nothing else. If you're torn between two ways of exposing an otherwise native API to java, use the simplest possible (return the HRESULT instead of throwing exceptions) and let a org.lwjgl.util.d3d class handle mappings to exceptions. This has the additional advantage of keeping the performance die-hards off your back, since you're not doing any "excess" processing getting in their way to high FPS numbers.

Trust me, it's hard enough to get the JNI interface to the native code working correctly, let alone mapping to java-like designs :)

- elias

princec

I'd also be sure to keep the "I" in interfaces, and preserve fully all the Microsoft/C capitalization, just as we have done for OpenGL. So it'd be HRESULT not HResult, and D3DPRESENT_PARAMETERS not D3DPersentParameters. This will make it all much more familiar to people coming from C++, and also much easier to understand and port all the millions of DX tutorials out there.

Cas :)

gaarazero

Going along those lines then, I had the idea of putting the enums that D3D uses into Java Enums.  I did it before and it makes the code look more like the original and is type safe.  The only down side is that if users don't have 1.5 or greater, it wont work.

-gz
JNewton 0.8 - Newton Dynamics wrapper for Java!
org.lwjgl.d3d - Currently Working On

princec

That's probably not so much of an issue as it at first sounds because most people can ship a current VM with bigger projects and for smaller projects... meh who cares :) About time people upgraded!

Cas :)