If you want to plug the renderer into your application, the easiest solution is perhaps use 'inc\real\code2\r3sare.h' class (sare stands for Stand Alone Rendering Engine. This class defines properties for full Realsoft Graphics Oy3D distributed network rendering engine and is easy to use.
For example, below is an example how to implement a batch renderer which can render any .r3d project.
#include <r3sare.h>
#include <r3app.h>
/* create app. object, as usual */
app = R3AppCreate(....);
/* register sare class and plug-ins from the 'plugins' folder */
R3RegisterSAREClass(app)
R3RegisterExternalClasses(app, "Plugins");
/* create distributed network renderer */
sare = R3New(R3CLID_SARE,
R3TAG_END);
if(sare) R3DoA(sare, R3RM_REF, NULL);
/* load in desired .r3d project */
ok = R3DoA(sare, R3SAREM_LOADPROJECT, "myproject.r3d");
/* prepare for rendering */
ok = R3DoA(sare, R3SAREM_INITRENDER, NULL);
/* start rendering */
ok = R3DoA(sare, R3SAREM_RENDER, NULL);
/* rendering runs asynchronously (possible over network)
so we have plenty of time to do something here */
ok = R3DoA(sare, R3SAREM_WAIT, NULL);
R3Do(sare, R3RM_UNREF, NULL);
R3AppDelete(app);
You can find the above example from 'sdk\samples\applications\render\batch' folder.
The rendering engine is fully configurable. Instead of linking full RS distributed network rendering to your application, you can link only those geometric primitives you really need. Just like everything else in Realsoft 3D, also the rendering engine is multi threading safe - you can use it from as many threads as you wish simultaneously.
Let's imagine your application needs to render a photo realistic spheres in Windows BMP format. To do this, you have to link the following classes to your application:
#include <r3freng.h> /* rendering engine */
#include <r3obmp.h> /* BMP file format */
#include <r3output.h> /* system which binds renderer to the final output (bmp, in this case) */
#include <r3sphere.h> /* sphere geometry */
#include <r3level.h> /* hierarchy level */
R3RegisterFREngineClass(app);
R3RegisterOutputClass(app);
R3RegisterBmpSettingsClass(app);
R3RegisterSphereClass(app);
R3RegisterLevelClass(app);
Let's assume you want to generate a bmp image whose resolution is 320 x 200 pixels. You also want to use perspective camera mode. Create a rendering engine object with the following attributes:
renderer = R3New(R3CLID_FRENGINE,
R3T(R3FRA_Projection, R3FR_PERSPECTIVE),
R3T(R3FRA_XResol, 320),
R3T(R3FRA_YResol, 200),
R3TAG_END);
To specify the file format for the renderer:
output = R3New(R3CLID_BMPSETTINGS,
R3T(R3OUTPA_Path, "filename.bmp"),
R3TAG_END);
R3DoA(output, R3OUTPM_MAKEDEFAULTBINDINGS, NULL);
R3DoA(renderer, R3FRM_REGISTEROUTPUT, output);
The R3OUTPM_MAKEDEFAULTBINDINGS method sets up default channel bindings (Red pixels are saved to 'Red' channel of the BMP image etc. You could also set up more interesting channel bindings, such as direct 'Z' to 'Red'). Note also that the rendering engine can render to any number of images simultaneously. Just create multiple output objects and pass them to the renderer via R3RFRM_REGISTEROUTPUT method.
The rendering engine is now fully configured and ready to render. Let's create the actual scene to be rendered. Our scene consists of one sphere and one camera objects:
root = R3New(R3CLID_LEVEL,
R3TAG_END);
rad = 0.5;
sphere = R3New(R3CLID_SPHERE,
R3T(R3PRIMA_Parent, root),
R3T(R3SPHA_Radius, &rad),
R3TAG_END);
VSet(&from, 0.0, 0.0, -1.0);
VSet(&dir, 0.0, 0.0, 0.0);
VSet(&up, 0.0, 1.0, 0.0);
camera = R3New(R3CLID_CAMERA,
R3T(R3PRIMA_Parent, root),
R3T(R3CAMA_Position, &from),
R3T(R3CAMA_Direction, &dir),
R3T(R3CAMA_Up, &up),
R3TAG_END);
Of course, all objects created above provide many other useful attributes which you could define. For example, the camera class defines depth-of-field, color of flash light, and so on.
The final thing is to send the scene to the renderer. To do this, call:
R3DoA(renderer, R3FRM_BEGINWORLD, NULL);
R3Do(scene, R3PRIMM_RENDER,
R3T(R3PRIMA_RenderEngine, renderer),
R3TAG_END);
R3DoA(renderer, R3FRM_ENDWORLD, NULL);
R3Dispose(root);
The final step is to ask the renderer to render the image by calling:
R3DoA(renderer, R3FRM_RENDER, NULL);
R3Dispose(renderer);
This deletes the rendering engine as well as registered image objects.
This example demonstrates how you can plug-in the rendering system to your application. Of course, you will have to be able to create much more than just spheres. For example, to make you application to support also nurbs surfaces, just include r3numesh.h and call R3RegisterNurbsMeshClass(). Then you can create and render nurbs meshes from your application!
You will need the following header files:
#include <r3typids.h> /* For general data storage type selections */
#include <r3color.h> /* Color data types */
#include <r3chcol.h> /* Color channel class */
#include <r3cha.h> /* Alpha channel class */
Rendering engine creation and scene description happens as before. The output definition goes as follows:
char *color_name, *a_name;
if (!(output = R3New(R3CLID_RAWIMAGESETTINGS,
R3T(R3OUTPA_Width, x_resol),
R3T(R3OUTPA_Height, y_resol),
R3T(R3OUTPA_KeepOutputObject, TRUE), /* Do not deallocate image data in R3OUTPM_END */
R3TAG_END)))
goto bail_out;
Important note: unlike in the previous .bmp rendering example, we will use the output object after the rendering. R3RM_REF keeps it alive for our use.
R3DoA(output, R3RM_REF, NULL);
/* Define which channels the raw image stores: */
R3GetClassAttrs(R3CLID_COLORCHANNEL, R3T(R3RCA_Name, &color_name), R3TAG_END);
if(!R3DoA3(output, R3RAWOSETM_ENABLECHANNEL, (void*)R3TID_BYTE, color_name, (void*)R3CLID_COLORCHANNEL))
goto bail_out;
R3GetClassAttrs(R3CLID_ALPHACHANNEL, R3T(R3RCA_Name, &a_name), R3TAG_END);
if(!R3DoA3(output, R3RAWOSETM_ENABLECHANNEL, (void*)R3TID_BYTE, a_name, (void*)R3CLID_ALPHACHANNEL))
goto bail_out;
if(!R3DoA(output, R3OUTPM_MAKEDEFAULTBINDINGS, NULL))
goto bail_out;
R3DoA(renderer, R3FRM_REGISTEROUTPUT, output);
R3DoA(renderer, R3FRM_RENDER, NULL);
Now we can examine the result image. It can be accessed using the methods defined in 'r3output.h'. Alternatively, one can use the lower level datatype object (see inc/real/dtype/r3rawim.h, r3dtype.h) for faster access. For example, image rows can be read as follows:
#include <r3rawim.h> /* the datatype class */
R3OBJ *dtypeobj;
int y;
R3UBYTE *bytebuffer; /* Allocate x_resol*3 (3 for RGB) bytes to this buffer */
R3GetAttrs(output, R3T(R3OUTPA_OutputObject, &dtypeobj), R3TAG_END);
R3DoA(dtypeobj, R3DTYPEM_BEGIN, NULL);
R3DoA(dtypeobj, R3RAWM_SELECTCHANNELBYNAME, color_name); /* Define what channel to read */
for(y=0; y<y_resol; y++) {
R3DoA2(dtypeobj, R3DTYPEM_GETROWRAW, (void*)y, (void*)bytebuffer);
/* Do something with the data */
}
R3DoA(dtypeobj, R3DTYPEM_END, NULL);
You can also use the data directly:
R3BYTECOLOR3 *rgb;
R3GetAttrs(output, R3T(R3OUTPA_OutputObject, &dtypeobj), R3TAG_END);
R3DoA(dtypeobj, R3DTYPEM_BEGIN, NULL);
R3DoA(dtypeobj, R3RAWM_SELECTCHANNELBYNAME, color_name); /* Define what channel to read */
R3GetAttrs(dtypeobj, R3T(R3DTYPEA_Data, &rgb), R3TAG_END); /* Fetch the current channel data address */
/* Then use the RGB data as you like */
R3DoA(dtypeobj, R3DTYPEM_END, NULL);
Remeber to kill the output object after finishing its use:
R3DoA(output, R3RM_UNREF, NULL);