This is an example of how to use the Nebula engine as a back-end renderer. Nebula
could probably be easily interfaced with
WorldFoundry in this way to use Nebula's
powerful rendering capabilities.
Original source:
http://nebuladevice.sourceforge.net/cgi-bin/twiki/view/Nebula/BoxBallDemo
Notes:
- the code inside while (gfx->Trigger() && running) does the rendering. This needs to be put inside the WorldFoundry main loop.
- The statement graph->Attach(root, 0); attaches the entire visual hierarchy (the root node) to the scenegraph, which is then rendered by Nebula by triggering the gfx server (this is why gfx->Trigger() is the while loop condition). Instead of attaching the entire visual hierarchy, WorldFoundry would attach only those visual nodes for those parts of the scene to be rendered - in the previous, current, and next rooms. Here it is clear how Nebula is carefully designed not to dictate any policy, so it can work with any visibility system.
- WorldFoundry needs to generate visual hierarchy nodes (probably at level load time) to send to Nebula; i.e. there needs to be a "parallel" database of Nebula visual objects, and WF merely decides which of these objects get drawn at which point in time. See InterfacingNebulaDeviceAndWorldFoundry
// This software is provided 'as-is', without any express or implied warranty. In no event will
// Nebula or the author be held liable for any damages arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose, including commercial
// applications, and to alter it and redistribute it freely. Technical support is not offered by
// Nebula or the author for this program. All I ask is that you send any modifications, big or
// small, you want to share to ddurocher@rica.net along with a full description as to what was
// changed or added so I can keep this tutorial/demo updated.
//-------------------------------------------------------------------
// This tutorial/demo is a scalped Gfxserv.cc for loading scripts (*.n and *.tcl). It's a very
// basic example of what can be done using Nebula. The objects were made in Lightwave and
// exported using Ilya Kliot's LWS to TND exporter.
//-------------------------------------------------------------------
// DESCRIPTION:
// A rotating textured ball moves from left to right while a rotating textured box does a figure
// 8 around it.
//-------------------------------------------------------------------
// All headers, classes, etc are located here.
#include "load_scripts.h"
int main(int argc, char *argv[])
{
char *port_name = "gfxserv";
char *server_class = "nglserver";
char *mode = "w(512)-h(512)";
char *script_server = "ntclserver";
bool grid = true;
bool nosleep = false;
const char* result;
// hier geht's los
V.ident();
vector3 t(0.0f,2.5f,0.0f);
V.translate(t);
// Start a new Kernel Server.
nKernelServer* ks = new nKernelServer;
// Startup the basic servers
nFileServer2* fs2 = (nFileServer2*) ks->New("nfileserver2", "/sys/servers/file2");
nGfxServer* gfx = (nGfxServer *) ks->New(server_class, "/sys/servers/gfx");
nInputServer* inp = (nInputServer *) ks->New("ninputserver", "/sys/servers/input");
nTclServer* script = (nTclServer *) ks->New(script_server, "/sys/servers/script");
nSceneGraph2* graph = (nSceneGraph2 *) ks->New("nscenegraph2", "/sys/servers/sgraph2");
nShadowServer* shadow = (nShadowServer *) ks->New("nsbufshadowserver", "/sys/servers/shadow");
nChannelServer* chn = (nChannelServer*) ks->New("nchannelserver", "/sys/servers/channel");
nConServer *con = (nConServer *) ks->New("nconserver", "/sys/servers/console");
nMathServer *math = (nMathServer *) ks->New("nmathserver", "/sys/servers/math");
nParticleServer *part = (nParticleServer *) ks->New("nparticleserver", "/sys/servers/particle");
nSpecialFxServer *fx = (nSpecialFxServer *) ks->New("nspecialfxserver", "/sys/servers/specialfx");
n3DNode *root = (n3DNode *) ks->New("n3dnode", "/usr/scene");
// Open Box
// RunScript = evaluate a script file.
// Lookup = Look up a path and return the corresponding nRoot object.
script->RunScript("..\\load_scripts\\box\\box.n",result);
box = (n3DNode*) ks->Lookup("/load_scripts/box");
// Open Ball
// RunScript = evaluate a script file.
// Lookup = Look up a path and return the corresponding nRoot object.
script->RunScript("..\\load_scripts\\ball\\ball.n",result);
ball = (n3DNode*) ks->Lookup("/load_scripts/ball");
// Define a new display mode. The new display mode will not show up until the
// display is actually (re-)opened via CloseDisplay()/OpenDisplay().
gfx->SetDisplayMode(mode);
//Open the display as defined by SetDisplayMode(). This will restore the app
//window and create a new d3d device.
gfx->OpenDisplay();
// If 'running' is set to false, the nGlServer Window will open then close
// automatically
bool running = true;
// Boolean Trigger() (true/false). If '&& running' is set to "&& !running", a
// LINK:fatal error LNK1168 will occur
while (gfx->Trigger() && running)
{
if (!script->Trigger()) running = false;
ks->Trigger();
ks->ts->Trigger();
// The purpose of GetFrameTime() is to get an exactly identical
// frame-timestamp within two nTimeServer::Trigger() calls
// (whereas a nTimeServer::GetTime() will return a different
// timestamp each time it is called).
double t = ks->ts->GetFrameTime();
inp->Trigger(t);
// Begin keyboard and mouse Input-Messages.
nInputEvent *ie;
// Go to the first input event
if ((ie = inp->FirstEvent()))
{
// Has a keyboard or mouse key been pressed? handleInput() is a user
// function
do handleInput(con,ie); while ((ie = inp->NextEvent(ie)));
inp->FlushEvents();
}
// Speed at which the screen moves when the keyboard or mouse keys are
// pressed. handleViewer() is a user made function.
handleViewer();
// Render Scene
if (gfx->BeginScene())
{
nRState rs;
matrix44 vwr;
vwr = V;
// inverts a 4x4 matrix consisting of a 3x3 rotation matrix and a
// translation (eg. everything that has [0,0,0,1] as the rightmost
// column) MUCH cheaper then a real 4x4 inversion.
vwr.invert_simple();
// trigger particle server
part->Trigger();
// Viewer-Matrix setzen
gfx->SetMatrix(N_MXM_VIEWER,V);
// Scenegraph vollrendern
chn->SetChannel1f(chn->GenChannel("time"), (float) t);
chn->SetChannel1f(chn->GenChannel("gtime"), (float) t);
// Begin the scene
if (graph->BeginScene(vwr))
{
fx->Begin();
// attach a visnode hierarchy to the scene.
graph->Attach(root, 0);
// GlEnd() - Not sure what this does.
fx->End(graph);
// end the scene.
graph->EndScene(true);
}
/* Render the grid on the screen with a blue background */
if (grid) {
rs.Set(N_RS_TEXTUREHANDLE,0); gfx->SetState(rs);
rs.Set(N_RS_LIGHTING,N_FALSE); gfx->SetState(rs);
// Set one of the modelview or projection matrices.
gfx->SetMatrix(N_MXM_MODELVIEW,vwr);
gfx->Begin(N_PTYPE_LINE_LIST);
// Set the background color here.
gfx->Rgba(0.1f,0.5f,2.0f,1.0f);
// Set the size of the grid here.
float p;
for (p=-25.0f; p<=+25.0f; p+=1.0f)
{
gfx->Coord(p, 0.0f, -25.0f);
gfx->Coord(p, 0.0f, +25.0f);
gfx->Coord(-25.0f, 0.0f, p);
gfx->Coord(+25.0f, 0.0f, p);
}
// End Gfxserver
gfx->End();
rs.Set(N_RS_LIGHTING,N_TRUE); gfx->SetState(rs);
}
/* End grid render */
// End this scene
gfx->EndScene();
}
}
// Close the display open by OpenDisplay(). This will minimize the app window and destroy
// the d3d device.
gfx->CloseDisplay();
if (root) root->Release();
if (part) part->Release();
if (math) math->Release();
if (con) con->Release();
if (chn) chn->Release();
if (shadow) shadow->Release();
if (graph) graph->Release();
if (script) script->Release();
if (gfx) gfx->Release();
if (inp) inp->Release();
if (fs2) fs2->Release();
if (load_scripts) load_scripts->Release();
if (box) box->Release();
if (ball) ball->Release();
delete ks;
return 0;
}