Skip to content

Instantly share code, notes, and snippets.

@jamesu
Created September 25, 2012 08:46
Show Gist options
  • Save jamesu/3780691 to your computer and use it in GitHub Desktop.
Save jamesu/3780691 to your computer and use it in GitHub Desktop.
Using the EngineAPI in Torque3D
// Note you will need to create a "getFunctionAddress" function in EngineFunctionInfo unless you use
// getProcAddress() & getBindingName() on the function exports.
void *getFunctionAddress() { return mAddress; }
//
// This example demonstrates the following:
// * calling "generateUUID" which is exported as a global function in the API.
// * constructing an instance of ColorI and setting its exposed fields.
//
// Note that the idea behind engineAPI is that you load the Torque3D dll then enumerate the API
// information and create a native binding for it. Using the information, you can construct a
// representation of every type the API uses, as well as call functions and methods.
//
// From what I can tell it's not really meant to be used internally, which kind of makes
// sense considering you can just stick stuff on the end of the DefineEngine* macros to generate an
// internal binding for your favourite scripting language.
//
// For something more c-like there is the API in "cinterface/" which is a wrapper for the console
// API, though that doesn't use the engineAPI stuff.
//
#include "console/engineAPI.h"
// Alternate representation of Torque::UUID
// Size determined by EngineTypeInfo::getTypeInfoByName("UUID")->getInstanceSize().
typedef struct TorqueUUID
{
char data[16];
} TorqueUUID;
// Alternate representation of ColorI
// It's best just to import "core/color.h" for this, but this is just an example.
typedef struct TorqueColorI
{
U8 r,g,b,a;
} TorqueColorI;
// Prototype for generateUUID
typedef TorqueUUID(*TorqueGenerateUUIDFunc)();
// Construct an instance of a type
// For simple types using the equivalent C++ class is probably a better idea, but this is just an example.
ConsoleFunction(testCreateEngineType, void, 1, 1, "")
{
const EngineTypeInfo *colorTypeInfo = EngineTypeInfo::getTypeInfoByName("ColorI");
U32 colorSize = colorTypeInfo->getInstanceSize();
U32 structSize = sizeof(TorqueColorI);
Con::printf("EngineAPI ColorI size: %i, Struct size: %i", colorSize, structSize);
TorqueColorI col;
// Consruct the ColorI in col
if (colorTypeInfo->constructInstance(&col)) {
Con::printf("Created ColorI");
// Enumerate the fields, set r,g,b,a to 0,1,2,3
const EngineFieldTable *fieldTable = colorTypeInfo->getFieldTable();
for (int i=0; i<fieldTable->getNumFields(); i++) {
const EngineFieldTable::Field field = (*fieldTable)[i];
U8 *ptr = (U8*)(&col) + field.getOffset();
*ptr = i;
Con::printf("Field: %s, Type == %s, Value == %i", field.getName(), field.getType()->getTypeName(), *ptr);
}
// Clean up instance
colorTypeInfo->destructInstance(&col);
}
}
// Enumerate the global function list, calling a function
ConsoleFunction(testCallEngineExport, void, 1, 1, "")
{
EngineExport *currentExport;
EngineExportScope *exports = EngineExportScope::getGlobalScope();
// First we need to initialize the engine API
engineAPI::gIsInitialized = true;
// Enumerate the root, only has 1 entry (the global scope)
for (currentExport = exports; currentExport; currentExport = currentExport->getNextExport()) {
const char *kindType = "Unknown";
switch (currentExport->getExportKind()) {
case EngineExportKindScope:
kindType = "Scope";
break;
case EngineExportKindFunction:
kindType = "Function";
break;
case EngineExportKindType:
kindType = "Type";
break;
}
Con::printf("Export: %s, Type=%s", currentExport->getExportName(), kindType);
// Check if this is a the global scope
EngineExportScope *scopeExport = dynamic_cast<EngineExportScope*>(currentExport);
if (!scopeExport)
continue;
// Enumerate the global scope. This contains global functions, classes, types, etc
for (EngineExport *subExport = scopeExport->getExports(); subExport; subExport = subExport->getNextExport()) {
//
const char *subKindType = "Unknown";
switch (subExport->getExportKind()) {
case EngineExportKindScope:
subKindType = "Scope";
break;
case EngineExportKindFunction:
subKindType = "Function";
break;
case EngineExportKindType:
subKindType = "Type";
break;
}
EngineTypeInfo *typeExport = dynamic_cast<EngineTypeInfo*>(currentExport);
Con::printf("Sub Export: %s, Type=%s", typeExport ? typeExport->getTypeName() : subExport->getExportName(), subKindType);
// If we encounter "generateUUID", call it
if (dStrcmp(subExport->getExportName(), "generateUUID") == 0) {
EngineFunctionInfo *funcExport = dynamic_cast<EngineFunctionInfo*>(subExport);
// Note: the intended method is to call getProcAddress() on funcExport->getBindingName(),
// but since we are doing this here we'll use a shortcut.
const EngineTypeInfo *type = EngineTypeInfo::getTypeInfoByName("UUID");
Con::printf("UUID SIZE == %i, struct size == %i", type->getInstanceSize(), sizeof(TorqueUUID));
// Call generateUUID with our TorqueUUID struct
TorqueGenerateUUIDFunc func = (TorqueGenerateUUIDFunc)funcExport->getFunctionAddress();
TorqueUUID uuid = func();
// Convert to a Torque::UUID and call toString()
TorqueUUID *uuidPtr = &uuid;
String uuidString = reinterpret_cast<Torque::UUID*>(uuidPtr)->toString();
Con::printf("Generated UUID: %s", (const char*)uuidString);
// Stop so we can see the result
return;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment