C Classes with Constructors, etc

BlitzMax Forums/BlitzMax Programming/C Classes with Constructors, etc

Gabriel(Posted 2006) [#1]
Yes, sorry, me again.

I've now got the basics sorted out for HGE. In other words, I've got all the virtual functions within the class working as they should. I can work with images, sounds, etc.

HGE has a series of helper classes to do advanced stuff though, and I'd like to get that done too. If it's possible. But these classes do not return instances via a public function, they do it only via constructors. So I really don't know how I would go about implementing this into BMax.

Here's the class from the C++ header file. Any tips and advice would be greatly appreciated. And if there's anything there which 100% absolutely cannot ever be done from BMax, I guess you might as well tell me now.

class hgeSprite
{
public:
	hgeSprite(HTEXTURE tex, float x, float y, float w, float h);
	hgeSprite(const hgeSprite &spr);
	~hgeSprite() { hge->Release(); }

	hgeSprite&	operator= (const hgeSprite &spr);


	void		Render(float x, float y);
	void		RenderEx(float x, float y, float rot, float hscale=1.0f, float vscale=0.0f);
	void		RenderStretch(float x1, float y1, float x2, float y2);
	void		Render4V(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3);

	void		SetTexture(HTEXTURE tex);
	void		SetTextureRect(float x, float y, float w, float h);
	void		SetColor(DWORD col, int i=-1);
	void		SetZ(float z, int i=-1);
	void		SetBlendMode(int blend) { quad.blend=blend; }
	void		SetHotSpot(float x, float y) { hotX=x; hotY=y; }
	void		SetFlip(bool bX, bool bY);

	HTEXTURE	GetTexture() const { return quad.tex; }
	void		GetTextureRect(float *x, float *y, float *w, float *h) const { *x=tx; *y=ty; *w=width; *h=height; }
	DWORD		GetColor(int i=0) const { return quad.v[i].col; }
	float		GetZ(int i=0) const { return quad.v[i].z; }
	int			GetBlendMode() const { return quad.blend; }
	void		GetHotSpot(float *x, float *y) const { *x=hotX; *y=hotY; }
	void		GetFlip(bool *bX, bool *bY) const { *bX=bXFlip; *bY=bYFlip; }

	hgeRect*	GetBoundingBox(float x, float y, hgeRect *rect) const { rect->Set(x-hotX, y-hotY, x-hotX+width, y-hotY+height); return rect; }
	hgeRect*	GetBoundingBoxEx(float x, float y, float rot, float hscale, float vscale,  hgeRect *rect) const;
	float		GetWidth() const { return width; }
	float		GetHeight() const { return height; }

protected:
	hgeSprite();
	static HGE	*hge;

	hgeQuad		quad;
	float		tx, ty, width, height;
	float		tex_width, tex_height;
	float		hotX, hotY;
	bool		bXFlip, bYFlip;
};



N(Posted 2006) [#2]
Try something like this:

#include "hgesprite.h"

// hgeSpriteWrapper.cpp
extern "C" __cdecl hgeSprite* CreateHGESprite(HTEXTURE t, float x, float y, float w, float h){
   return new hgeSprite(t, x, y, w, h);
}

extern "C" __cdecl hgeSprite* CopyHGESprite(hgeSprite* s){
   return new hgeSprite(*s);
}

extern "C" __cdecl void DestroyHGESprite(hgeSprite* s){
   delete s;
}


Extern "C"
   Function CreateHGESprite:hgeSprite( t%, x#, y#, w#, h# )
   Function CopyHGESprite:hgeSprite( p:hgeSprite )
   Function DestroyHGESprite( p:hgeSprite )
End Extern



Gabriel(Posted 2006) [#3]
Ok, here's what I've done.

hgehelp Module
Strict

Module glimmer.hgehelp

ModuleInfo "Version 1.0"
ModuleInfo "Author: Phil Ings"


Import "-lhge"
Import "-lhgehelp"

Import "hgehelpwrapper.cpp"


Extern "C"
   Function CreateHGESprite:hgeSprite( t%, x#, y#, w#, h# )
   Function CopyHGESprite:hgeSprite( p:hgeSprite )
   Function DestroyHGESprite( p:hgeSprite )
End Extern



Extern "Win32"

	Type hgeSprite
			
		Method Constructor1:hgeSprite(Tex:Int,X:Float,Y:Float,W:Float,H:Float)
		Method Constructor2(Spr:hgeSprite)
		Method Destructor()
		
		Method Operator:hgeSprite(Spr:hgeSprite)
	
		Method Render(X:Float,Y:Float)
		Method RenderEx(X:Float,Y:Float,Rot:Float,HScale:Float,VScale:Float)
		Method RenderStretch(X1:Float,Y1:Float,X2:Float,Y2:Float)
		Method Render4V(X0:Float,Y0:Float,X1:Float,Y1:Float,X2:Float,Y2:Float,X3:Float,Y3:Float)
		
		Method SetTexture(Tex:Int)
		Method SetTextureRect(X:Float,Y:Float,W:Float,H:Float)
		Method Set_Color(Col:Int,I:Int)
		Method SetZ(Z:Float,I:Int)
		Method SetBlendMode(Blend:Int)
		Method SetHotSpot(X:Float,Y:Float)
		Method SetFlip(BX:Int,BY:Int)
		
		Method GetTexture:Int()
		Method GetTextureRect(X:Float Var,Y:Float Var,W:Float Var,H:Float Var)
		Method Get_Color:Int(I:Int)
		Method GetZ:Float(I:Int)
		Method GetBlendMode:Int()
		Method GetHotSpot(X:Float Var,Y:Float Var)
		Method GetFlip(BX:Float Var, BY:Float Var)
		
		Method GetBoundingBox:Int(X:Float,Y:Float,Rect:Int) ' RETURNS AND TAKES hgeRect REALLY
		Method GetBoundingBoxEx:Int(X:Float,Y:Float,Rot:Float,HScale:Float,VScale:Float,Rect:Int) ' RETURNS AND TAKES hgeRect REALLY
		Method GetWidth:Float()
		Method GetHeight:Float()
		
		Method _hgeSprite()
		
		Field Quad:Int ' ACTUALLY IT IS AN hgeQuad
		Field TX:Float
		Field TY:Float
		Field Width:Float
		Field Height:Float
		Field HotX:Float
		Field HotY:Float
		Field BXFlip:Int,BYFlip:Int

	End Type

End Extern


And the CPP as you have it listed above. I get a memory access violation if I call any of the methods though, so I don't think I've got it quite right.

And yes, I know a couple of classes I haven't done yet have been replaced with Ints, but those are not the ones I'm calling, and there's no point me doing every class until I've got my technique down pat.

The functions are not returning null hgeSprite's BTW. I check for that.


skidracer(Posted 2006) [#4]
Unfortunately I don't think you are going to get very far interfacing to C++ objects like the above that features non virtual methods without wrapping them all in C.

From what I can understand BlitzMax depends on an Extern Type's Methods being present in the classes virtual function table so any method not declared virtual will not be allocated a slot in the table.

If you can rebuild the C++ you may be able to add a virtual declaration to all the c++ methods to avoid having to wrap.


Gabriel(Posted 2006) [#5]
I'm not sure if I fancy rebuilding the DLL, considering my lack of knowledge of C. Would writing a wrapper be as simple as returning a pointer in the functions that Noel gave then writing similar functions which take a pointer as well as whatever else they take? So in other words, each wrapped function would just be a one line function to call the method of the type instance passed from BMax?