L3DT development blog
Large 3D terrain generator

News for November 2006

November 9

Programming style

The next release of the plugin API will come with some 'wrapper' classes to make the lives of plugin developers just a little bit easier (if they choose to use them, that is.) In this post I'm going to demonstrate the changes by writing the same piece of plugin code with and without the wrapper classes. This particular example retrieves the heightfield, asks the user for a 'level' value (float), and then sets every pixel in the heightfield to that value.

Firstly, the basic API code:

// get the heightfield
ZMAP hMap;
if(!(hMap = theAPI.map_GetMap("project.HF")))
  return false;
 
// check that it is a heightfield
if(theAPI.map_GetMapType(hMap)!=MAP_Heightfield)
  return false;
 
// create a temp var for the level setting
ZVAR hVar;
if(!(hVar = theAPI.var_Create(VarID_float, "level")))
  return false;
 
// open edit user interface for level setting
if(!theAPI.var_EditUI(hVar, "Enter level (m)")) {
  theAPI.var_Delete(hVar);
  return false;
}
 
// get the value
float level;
theAPI.var_GetValueEx(hVar, VarID_float, &level);
 
// apply level setting to all pixels in map
bool ErrorFlag = false;
for(int j=0; j<theAPI.map_GetHeight(hMap) && !ErrorFlag; j++) {
  for(int i=0; i<theAPI.map_GetWidth(hMap) && !ErrorFlag; i++) {
    if(!theAPI.map_SetPixel(hMap, i, j, &level)) {
      ErrorFlag = true;
    }
  }
}
 
// cleanup
theAPI.var_Delete(hVar);
 
if(ErrorFlag)	return false;
 
return true;

I think you'll agree that was a little torturous, particularly with all those brackets, ZVAR handles and function calls to 'theAPI'. Note I also had to be careful to delete the temporary hVar I had created, as forgetting to do so would have leaked a few bytes of memory.

Here is the code again, using the CzMap and CzVar wrappers:

// get the heightfield
CzMap zmap;
if(!zmap.GetByName("project.HF"))
  return false;
 
// check that it is a heightfield
if(zmap.GetMapType()!=MAP_Heightfield)
  return false;
 
// create a temp var for the level setting
CzVar TempVar;
if(!TempVar.Create(VarID_float, "level"))
  return false;
 
// open edit user interface for level setting
if(!theAPI.var_EditUI(TempVar.GetZVAR(), "Enter level (m)"))
  return false;
 
// get the value
float level;
TempVar.GetValue(VarID_float, &level);
 
// apply level setting to all pixels in map
bool ErrorFlag = false;
for(int j=0; j<zmap.ny() && !ErrorFlag; j++) {
  for(int i=0; i<zmap.nx() && !ErrorFlag; i++) {
    if(!zmap.SetPixel(i, j, &level)) {
      ErrorFlag = true;
    }
  }
}
 
if(ErrorFlag)	return false;

There are probably two things to notice here. One is that we're now using object oriented programming, so we've largely dispensed with the ZVAR handles and theAPI calls. The second is that the variables now obey scoping rules, so I don't have to call 'theAPI.var_Delete(hVar);' to clean up any more, and I don't have to worry about leaking memory.

Finally, for one last comparison, here is the equivalent 'native' code from L3DT:

// get the heightfield
CMapWrap* pMap;
if(!GetMap("HF", &pMap))
  return false;
 
// check that it is a heightfield
if(!pMap->IsInitType(MAP_Heightfield))
  return false;
 
// create a temp var for the level setting
CVar TempVar;
float* pFloat;
if(!TempVar.CreateAndGetData(VTID_float, "level", (void**)&pFloat))
  return false;
 
// open edit user interface for level setting
if(!VarUI_EditVar(&TempVar, "Enter level (m)"))
  return false;
 
// apply level setting to all pixels in map
bool ErrorFlag = false;
for(int j=0; j<pMap->ny() && !ErrorFlag; j++) {
  for(int i=0; i<pMap->nx() && !ErrorFlag; i++) {
    if(!pMap->SetPixel(i, j, pFloat)) {
      ErrorFlag = true;
    }
  }
}
 
if(ErrorFlag)	return false;
 
return true;

This is all object oriented too, and slightly more terse, but you'll note that it uses lots of pointers, and also some pointers to pointers. The plugin API, with wrapper classes, hides this complexity without compromising utility. I hope you'll like using it as much as I do.

Cheers, Aaron.

Update

The wrapper-ification is complete (for now.) I've added wrappers for generic variables, strings, variable lists, maps, file formats, extension functions, buffers, and progress boxes. There should be an updated API released next week sometime.

2011/01/13 07:34
 
l3dt/2006/nov.txt · Last modified: 2017/08/31 06:25 (external edit)
 
Except where otherwise noted, content on this wiki is licensed under the following license:CC Attribution-Share Alike 3.0 Unported
L3DT Development Blog RSS Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki