Game Development Community

How to define a new engine type

by Nathan Bowhay - ESAL · in Torque 3D Professional · 10/16/2010 (1:37 am) · 10 replies

I have structure similar to a Point3D and I was wondering how to define it as a new engine type so I can uses it in console methods.

Here is my example class:
class GeoPoint
{
public:
    F64 lat;
    F64 lon;
    F64 alt;

public:
    GeoPoint() : lat(0), lon(0), alt(0) {};
...
}

Here is an example method:
DefineConsoleMethod( MyClass, SetOrigin, void, ( GeoPoint origin),,
	"Set the origin point.n"
	"@param origin The origin to define for the object using latitude, longitude, altitude.n")
{
	object->SetOrigin(origin);
}

I think you get the what I am trying to do, but feel free to ask more questions if you need me to clarify.

NOTE: Now that I noticed it Point3D doesn't work either.

#1
10/16/2010 (1:55 am)
Does F64 even work in TorqueScript?

Have you thought about using Point3F with X Y and SQRT(Z) for Lat, Lon and Alt
#2
10/16/2010 (2:30 am)
No it doesn't completely. I am going to make several other changes to get F64 to work and posted about that here: www.torquepowered.com/community/forums/viewthread/121469

The problem is if I use floats there are several conversions and calculations being done where precision will be lost.

For instance I have a global object to handle where my offset is, so all the objects in my world are offset by that. I also get a lat, lon, alt through the network, I then have to convert that to a relative position for torque to use. So I get Lat, Lon, Alt that gets converted to a ECEF. Then I get the ECEF of my origin and subtract the two to figure out my offset in meters where my object will be. If you look at the conversion functions for lat, lon, alt to ECEF there is a lot of math being done with very small numbers. For instance it uses Eulers number as well as 1/298.257224. Here is a link to the math: mathforum.org/library/drmath/view/51832.html.

I mean basically I am converting a co-ordinate to represent a single point on the earth to a relative point in meters and this is going to be done quit often (several times a second).
#3
10/16/2010 (2:41 am)

To define the struct type, simply use DECLARE_STRUCT and IMPLEMENT_STRUCT like you can see, for example, for ColorI in engineStructs.h/cpp. The DECLARE_STRUCT must be in a header which must be included by all engineAPI functions/methods that use that the type.

To make this work with the console system, you also need a console getter and setter. Look at the definitions for TypeColorI in consoleTypes.h/cpp for an example.

To work with individual F64 values, see my post in your other thread.

BTW, use const GeoPoint& in your argument there for SetOrigin instead of just GeoPoint.
#4
10/21/2010 (1:15 am)
Ok so what I did was in mathTypes.h I added DECLARE_STRUCT( Point3D ); under all the others.
Then added DefineConsoleType( TypePoint3D, Point3D ) under the others.

I then added this in mathTypes.cpp:
//-----------------------------------------------------------------------------
// TypePoint3D
//-----------------------------------------------------------------------------
ConsoleType( Point3D, TypePoint3D, Point3D )
ImplementConsoleTypeCasters(TypePoint3D, Point3D)

ConsoleGetType( TypePoint3D )
{
   Point3D *pt = (Point3D *) dptr;
   char* returnBuffer = Con::getReturnBuffer(256);
   dSprintf(returnBuffer, 256, "%.9g %.9g %.9g", pt->x, pt->y, pt->z);
   return returnBuffer;
}

ConsoleSetType( TypePoint3D )
{
   if(argc == 1)
      dSscanf(argv[0], "%.9g %.9g %.9g", &((Point3D *) dptr)->x, &((Point3D *) dptr)->y, &((Point3D *) dptr)->z);
   else if(argc == 3)
      *((Point3D *) dptr) = Point3D(dAtod(argv[0]), dAtod(argv[1]), dAtod(argv[2]));
   else
      Con::printf("Point3D must be set as { x, y, z } or \"x y z\"");
}

I then defined a method using it:
DefineConsoleMethod( Earth, LocalToGeo, Point3D, ( Point3D local ),,
	"Convert the given local Cartesian position to Geodetic (latitude, longitude, altitude).\n"
	"@param local Local cartesian position.\n"
	"@return Geodetic coordinate converted from a local cartesian position.\n" )
{
	Cartesian tempLocal(local);
	Geodetic geoCord;
	object->LocalToGeo(tempLocal, &geoCord);
	return Point3D(geoCord.lat, geoCord.lon, geoCord.alt);
}

When I call something like this in script:
%x = 5.001;
%y = 5.001;
%z = 5.001;
MyEarth.LocalToGeo(%x, %y, %z);

In script I get 2 errors:
Error 1: MyEarth::LocalToGeo - wrong number of arguments (got 5, expected min 3 and max 3).
Error 2: usage: Convert the given local Cartesian position to Geodetic (latitude, longitude, altitude).

I also set a break point in mathTypes.cpp under the ConsoleSetType and argc seems to be 1 and when it should be 3. I tried passing it as one argument and the values get converted very wrongly.

What is going on? Any suggestions?
#5
10/21/2010 (1:23 am)
Sorry I also added this code in mathTypes.cpp:

IMPLEMENT_STRUCT( Point3D,
   Point3D, MathTypes,
   "" )

      FIELD( x, x, 1, "X coordinate." )
      FIELD( y, y, 1, "Y coordinate." )
      FIELD( z, z, 1, "Z coordinate." )

END_IMPLEMENT_STRUCT;
#6
10/21/2010 (1:28 am)

You need to call LocalToGeo like

MyEarth.LocalToGeo( %x SPC %y SPC %z );

The console method you have defined expects a single string argument that represents a Point3D. This argument is parsed through the ConsoleSetType code you have defined.
#7
10/21/2010 (2:06 am)
So I tried that and ended up getting weird values.

Plus According to:
ConsoleSetType( TypePoint3D )
there is a if that checks the number of arguments so it should work either way, shouldn't it? Why is argc always 1?

My main question was about the odd values I was getting. When I am back at work tomorrow I can give you an example. But the short of it is that when I set a break point in DefineConsoleMethod and pass something in using %x SPC %y SPC %z. I get something like -1.END or 24.00000... So something odd is happening.
#8
10/21/2010 (2:30 am)
Re argc==1:

The console system uses that to allow the console set/get functions to have alternate syntaxes where multiple individual component strings are used instead of all components mixed into one string. However, out of the top of my head, I'm not even sure that is used anywhere at all. If you just implement the argc==1 case, you should be fine.

Re conversion:

Your component fields are 64bits, rights? If so, you are using the wrong format specifier. %g expects a float and not a double so what gets written to memory there is nonsense. You need to use %lg.
#9
10/21/2010 (6:02 pm)
cool that worked. I am a bit curious though why it is lower case l: http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/

Does torque use lowercase and not just wrap sprintf.
#10
10/21/2010 (6:17 pm)

Glad it worked.

It's lowercase because %Lg is for long double (80 bits on x86) instead of just double (64 bits). Torque does wrap the standard library functions here.