/* * Author: Andrew Mann * * Copyright (C) 2004 PlaneShift Team (info@planeshift.it, * http://www.planeshift.it) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include "cssysdef.h" #include "iutil/objreg.h" #include "iutil/plugin.h" #include "iutil/vfs.h" #include "iutil/virtclk.h" #include "iutil/csinput.h" #include "iutil/eventq.h" #include "iutil/event.h" #include "iutil/document.h" #include "ivideo/graph3d.h" #include "ivideo/graph2d.h" #include "imap/ldrctxt.h" #include "imap/loader.h" #include "imap/reader.h" //#include "csutil/sysfunc.h" //#include "ivaria/reporter.h" //#include "ivaria/stdrep.h" #include "iengine/engine.h" #include "iengine/camera.h" #include "iengine/sector.h" #include "iengine/material.h" #include "iengine/texture.h" #include "ivideo/material.h" #include "cstool/csview.h" #include "imesh/thing.h" #include "iengine/mesh.h" #include "imesh/object.h" #include "imesh/particles.h" #include "igraphic/imageio.h" #include "cstool/initapp.h" #include "csutil/cmdhelp.h" #include "csutil/event.h" // PAWS stuff #include "paws/pawsmanager.h" #include "paws/pawsmainwidget.h" // Application paws widgets #include "paws/pawsfilenavigation.h" #include "gui_menubar.h" #include "pawsscrollpane.h" #include "pawscollapsablewidget.h" #include "gui_material.h" #include "gui_particlesystem.h" #include "gui_pslist.h" #include "gui_colorrow.h" // NR stuff #include "ivideo/shader/shader.h" #include "pv_helpers.h" #include "pv_resmgr.h" //#include "heightgrid.h" #include "partview.h" CS_IMPLEMENT_APPLICATION // Initialize globals/statics PartViewApp *PartViewApp::g_pApp=NULL; // // Startup function // int main(int argc, char *argv[]) { // CreateEnvironment prepares CS for use. // Part of preparation is creating the object registry, which is returned upon success iObjectRegistry *object_reg = csInitializer::CreateEnvironment(argc,argv); // Instanciate the application class PartViewApp::g_pApp = new PartViewApp(object_reg); // Initialize and run the application if (PartViewApp::g_pApp && PartViewApp::g_pApp->Initialize()) PartViewApp::g_pApp->Run(); delete PartViewApp::g_pApp; PartViewApp::g_pApp=NULL; // Clean up CS stuff csInitializer::DestroyApplication(object_reg); return 0; } PartViewApp::PartViewApp(iObjectRegistry *object_reg) { // Set our local pointer to the object registry this->object_reg=object_reg; rotX=rotY=0.0f; // Default to showing the window window_visible=true; last_int_x=last_int_z=0xFFFFFFFF; mouse_left_down=mouse_right_down=false; menubar=NULL; matlistgui=NULL; pslistgui=NULL; resource_manager=NULL; } PartViewApp::~PartViewApp() { } bool PartViewApp::Initialize() { // Perform any initialization that might be able to fail here // The config file manager for CS pre-loads the VFS plugin and then reads a specified config file // which may specify some engine settings if ( !csInitializer::SetupConfigManager(object_reg, "/this/partview.cfg")) { // Initialization of config file failed #ifdef _RPTF0 _RPTF0(_CRT_WARN,"PartViewApp::Initialize() - csInitializer::SetupConfigManager() failed!"); #endif return false; } // Request the plugins that we need to function if (!csInitializer::RequestPlugins(object_reg, CS_REQUEST_VFS, // VFS - The Virtual File System plugin. This allows CS to map a standard format of resource paths and names onto the // differing filesystems it can run on (windows and linux for example). If something needs to be loaded from disk, VFS is needed. // Pretty much every application will make use of VFS CS_REQUEST_OPENGL3D, // Need the OpenGL 3D renderer to display output to screen CS_REQUEST_ENGINE, // The CS engine tracks things including sectors, meshes, materials, etc CS_REQUEST_IMAGELOADER, // The imageloader will let us load images like textures for our walls automatically CS_REQUEST_LEVELLOADER, // LevelLoader must be specified along with imageloader CS_REQUEST_REPORTER, CS_REQUEST_REPORTERLISTENER, // The reporter handles receiving reports (warning/error output) and the listener handles outputting it CS_REQUEST_PLUGIN("crystalspace.documentsystem.xmlread", iDocumentSystem), CS_REQUEST_END // Mark the end of requests )) { // Initialization of plugins failed - probably not all of them are present / able to be found #ifdef _RPTF0 _RPTF0(_CRT_WARN,"PartViewApp::Initialize() - Could not initialize plugins!"); #endif return false; } // Setup static event handler callback if (!csInitializer::SetupEventHandler(object_reg,StaticEventHandler)) { // The reporter is setup now, so using that instead of the RPT debug macros csReport(object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Could not initialize event handler."); return false; } // Check to see if the --help option was specified on the command line if (csCommandLineHelper::CheckHelp(object_reg)) { csReport(object_reg, CS_REPORTER_SEVERITY_NOTIFY,"PartViewApp::Initialize()","This is a MainApp application. There is no help, dolt!"); // Display the CS options anyway csCommandLineHelper::Help (object_reg); return false; } csRef pluginmgr = CS_QUERY_REGISTRY(object_reg, iPluginManager); if (!pluginmgr.IsValid()) { csReport(object_reg, CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iPluginManager interface in the available plugins!"); return false; } // Start finding the interfaces to some of the plugins we loaded // The virtual clock. vc = CS_QUERY_REGISTRY (object_reg, iVirtualClock); if (!vc.IsValid()) { // Crystal Space uses SmartPointers for almost every pointer return. // SmartPointers are a small wrapper template class around a pointer that attempts to function as transparently as possible. // SmartPointers automatically adjust a reference count based on the number of SmartPointers to a given object that are in existance. // When the count reaches 0, the object is deleted. // In this way, some memory leaks are avoided, and reference counting does not have to be performed manually. // csReport(object_reg, CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iVirtualClock interface in the available plugins!"); return false; } // The CS graphics engine engine = CS_QUERY_REGISTRY (object_reg, iEngine); if (!engine.IsValid()) { csReport(object_reg, CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iEngine interface in the available plugins!"); return false; } // The 3D Renderer. g3d = CS_QUERY_REGISTRY (object_reg, iGraphics3D); if (!g3d.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iGraphics3D interface in the available plugins!"); return false; } // The keyboard input driver. kbd = CS_QUERY_REGISTRY (object_reg, iKeyboardDriver); if (!kbd.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iKeyboardDriver interface in the available plugins!"); return false; } // The Crystal Space file parser plugin interface - called 'iLoader'. loader = CS_QUERY_REGISTRY (object_reg, iLoader); if (!loader.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iLoader interface in the available plugins!"); return false; } // The Crystal Space Virtual File System interface vfs = CS_QUERY_REGISTRY (object_reg, iVFS); if (!vfs.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iVFS interface in the available plugins!"); return false; } // The shader plugins make heavy use of string sets. Stringsets are registered lists of strings converted into integer indexes // for fast comparison csRef strings = CS_QUERY_REGISTRY_TAG_INTERFACE (object_reg, "crystalspace.shared.stringset", iStringSet); if (!strings.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iStringSet interface in the available plugins!"); return false; } // We also need a iDocumentSystem and an iDocument to parse the shader definition file for us csRef docsys (CS_QUERY_REGISTRY(object_reg, iDocumentSystem)); if (!docsys.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iDocumentSystem interface in the available plugins!"); return false; } // Get the 2D rendering interface from the 3D rendering interface g2d = g3d->GetDriver2D(); if (!g2d.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not retrieve iGraphics2D interface from g3d->GetDriver2D()!"); return false; } // The plugin manager, which allows us to have better control of loading plugins. We need this to load a plugin and get a pointer to // an interface which many different plugins support plgmgr = CS_QUERY_REGISTRY (object_reg, iPluginManager); if (!plgmgr.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iPluginManager interface in the available plugins!"); return false; } // The iLoaderPlugin interface for the particles loader particlesloader=CS_LOAD_PLUGIN(pluginmgr,"crystalspace.mesh.loader.factory.particles",iLoaderPlugin); if (!particlesloader.IsValid()) { csReport(object_reg, CS_REPORTER_SEVERITY_ERROR, "MainApp::Initialize()","Could not find an iLoaderPlugin interface for 'crystalspace.mesh.loader.factory.particles'!"); return false; } // OpenApplication performs some CS startup tasks such as initializing all the previously requested plugins if (!csInitializer::OpenApplication (object_reg)) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","csInitializer::OpenApplication() failed!"); return false; } // PAWS window manager creation paws = new PawsManager(object_reg); if (!paws) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","PawsManager could not be instanciated!"); return false; } // Create the top level paws interface 'widget' (window) mainWidget = new pawsMainWidget(paws); if (!mainWidget) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","pawsMainWidget could not be instanciated!"); return false; } // Assign this widget as the current top level widget paws->SetMainWidget(mainWidget); // Helper function which registers any custom paws widgets that are used in this application // defined below RegisterPawsFactories(); // Load all the registered widgets if (!LoadPawsWidgets()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","LoadWidgets() signaled bad return."); return false; } // Setup standard PAWS mouse cursor paws->GetMouse()->ChangeImage("Standard Mouse Pointer"); // Create the resource manager resource_manager=new PVResourceManager(object_reg); //// // Basic initialization is complete. Begin to setup the render environment //// // Don't use any lighting cache at this time. engine->SetLightingCacheMode(0); // Create the sector - a logical area where our walls, lights, and camera will be placed // The name can be anything, but must be unique. Since we only have 1 sector we don't need to worry about that. the_room = engine->CreateSector("sector0"); CreateDefaultRoom(); /* LoadMapFileAsRoom("/this/art/world/hydlaa.zip"); iSectorList *sectorlist=engine->GetSectors(); if (sectorlist) { if (sectorlist->GetCount() > 0) the_room=sectorlist->Get(0); the_room-> } */ // Now that we have a room, create our camera and put it inside. // When constructing a view, the CS engine interface and 3d rendering interface must be passed. view = csPtr (new csView (engine, g3d)); // Put the camera inside of our sector view->GetCamera ()->SetSector (the_room); // Set the position of the camera to 0,5,-3 - not quite in the middle of the room view->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3)); // The view dimensions should match the dimensions of the viewport on your monitor. // To do that, we need to get the 2d rendering interface and see what the dimensions are iGraphics2D* g2d = g3d->GetDriver2D (); view->SetRectangle (0, 0, g2d->GetWidth (), g2d->GetHeight ()); /* //// // Test object(s) // // The objects created from this point on are testing various pieces of the engine // //// csRef img = loader->LoadImage("/lib/std/stone4.gif"); if (!img.IsValid()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error loading '/lib/std/stone4.gif' as image!"); return false; } csRef selimg = loader->LoadImage("/lib/std/white128.gif"); if (!selimg.IsValid()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error loading '/lib/std/white128.gif' as image!"); return false; } // Find the heightgrid plugin // csRef hg_plugin = CS_QUERY_REGISTRY_TAG_INTERFACE (object_reg, "crystalspace.mesh.object.rhad.heightgrid", iHeightGridPlugin); csRef hg_plugin = CS_QUERY_REGISTRY(object_reg, iHeightGridPlugin); if (!hg_plugin.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iHeightGridPlugin interface for heightgrid in the available plugins!"); return false; } csRef mesh_fact = hg_plugin->NewFactory(); if (!mesh_fact.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not create a heightgrid factory from the plugin!"); return false; } hg_fact=SCF_QUERY_INTERFACE(mesh_fact,iHeightGridFactory); if (!hg_fact.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not retrieve an iHeightGridFactory interface from the factory!"); return false; } // Initialize the factory hg_fact->SetColoringImage(img); hg_fact->SetMapScalingFactorX(4.0); hg_fact->SetMapScalingFactorZ(4.0); hg_fact->SetHeightBiasFactor(1.0f); if (gui_menu_widget) { gui_menu_widget->SetScaleVal(1.0f); gui_menu_widget->SetBiasVal(1.0f); } hg_mesh=mesh_fact->NewInstance(); hg_meshwrapper=engine->CreateMeshWrapper(hg_mesh,"HeightGrid",the_room); */ /* heightgrid=new HeightGrid(object_reg,g3d,engine); heightgrid->InitFromImage(img,selimg,the_room,6.0f); // heightgrid->HeightFromImage(img,1.0f,0.0f); heightgrid->Place(csVector3(-3.0f,2.0f,-3.0f)); /* // A cube in the center of the room - with a shader // Create an empty document to read the shader specification into csRef shaderDoc = docsys->CreateDocument (); // Now we open the shader file using VFS csRef shaderFile = vfs->Open ("/shader/cg_parallax.xml", VFS_FILE_READ); // And parse the XML formatted shader into the iDocument shaderDoc->Parse (shaderFile); // Now we need to get an interface to the shader manager which will allow us to compile and register this shader csRef shmgr (CS_QUERY_REGISTRY(object_reg, iShaderManager)); // And get the XMLShader compiler, which is used for all the shader top level definitions csRef shcom (shmgr->GetCompiler ("XMLShader")); // Compile the shader XML into a shader object which can later be applied to the material csRef shader = shcom->CompileShader (shaderDoc->GetRoot ()->GetNode ("shader")); // Create a material using a shader to apply to the faces of the cube csRef shadertex_handle = loader->LoadTexture("/lib/std/stone4.gif"); if (!shadertex_handle.IsValid()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error loading '/lib/std/stone4.gif' as texture"); return false; } csRef shadertex_wrapper = engine->GetTextureList()->NewTexture(shadertex_handle); if (!shadertex_wrapper.IsValid()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error adding '/lib/std/stone4.gif' texture to the engine texture list"); return false; } csRef shadermat = engine->CreateBaseMaterial(shadertex_wrapper); if (!shadermat.IsValid()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error creating material using '/lib/std/stone4.gif' as texture"); return false; } // The shader uses a single texture, which must be specified as a ShaderVariable csRef attributevar (csPtr ( new csShaderVariable (strings->Request ("tex diffuse")))); attributevar->SetValue (shadertex_wrapper->GetTextureHandle()); shadermat->AddVariable (attributevar); attributevar = csPtr (new csShaderVariable(strings->Request("heightmap"))); attributevar->SetValue (shadertex_wrapper->GetTextureHandle()); shadermat->AddVariable (attributevar); // Apply the shader to this material shadermat->SetShader(strings->Request ("OR compatibility"),shader); // Add this material to the engine's list of materials. This creates a wrapper which the engine // uses to access the material. csRef shadermat_wrapper = engine->GetMaterialList ()->NewMaterial (shadermat, "shadermaterial"); // Create the cube object csRef cube (engine->CreateThingMesh(the_room, "cube")); csRef cube_thingstate = SCF_QUERY_INTERFACE (cube->GetMeshObject (), iThingState); csRef cube_state = cube_thingstate->GetFactory (); cube_state->AddOutsideBox(csVector3(-1,4,-1),csVector3(1,6,1)); cube_state->SetPolygonMaterial(CS_POLYRANGE_LAST,shadermat_wrapper); cube_state->SetPolygonTextureMapping(CS_POLYRANGE_LAST,3); */ // Create a particle system /* csRef ps_fact_wrapper = engine->CreateMeshFactory("crystalspace.mesh.object.particles","crystalspace.mesh.object.particles"); if (!ps_fact_wrapper.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not create an iMeshFactoryWrapper for crystalspace.mesh.object.particles!"); return false; } csRef ps_factory = ps_fact_wrapper->GetMeshObjectFactory(); csRef ps_factory_state = SCF_QUERY_INTERFACE(ps_factory,iParticlesFactoryState); iMaterialWrapper* stone_wrapper = engine->GetMaterialList ()->FindByName ("stone"); ps_factory_state->SetMaterial(stone_wrapper); ps_factory_state->SetAutoStart(true); ps_factory_state->SetParticlesPerSecond(15); ps_factory_state->SetPointEmitType(); ps_factory_state->SetEmitTime(1000.0); csRef particle_system = ps_factory->NewInstance(); csRef ps_wrapper = engine->CreateMeshWrapper(particle_system,"partsys",the_room,csVector3(0,5,0)); PartSystemTracker *ps_track = new PartSystemTracker(particle_system,"Initial System"); particle_systems.Push(ps_track); */ // Load some default materials loader->LoadTexture ("raindrop", "/lib/std/raindrop.png"); loader->LoadTexture ("portaloverlay", "/lib/std/portaloverlay.jpg"); loader->LoadTexture ("snow", "/lib/std/snow.png"); loader->LoadTexture ("spark", "/lib/std/spark.png"); // Now we tell the engine that we've finished creating our world geometry and lights and that it should // calculate its lightmaps and release any interim loading formats. engine->Prepare (); /* testarrow=new DirectionArrow(object_reg,the_room,csVector3(0,5,0),csVector3(0,1,1),0.1f); if (!testarrow->Initialize()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error creating test arrow!"); return false; } CoordinateArrows *coord_arrows=new CoordinateArrows(object_reg,the_room,csVector3(0,5,0),csVector3(0,1,0),csVector3(1,0,0),1.0f,0.1f); if (!coord_arrows->Initialize()) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error creating coordinate arrows!"); return false; } */ resource_manager->Material_AddAllMaterialsInEngine(); matlistgui=(guiMaterialList *)paws->FindWidget("materiallist"); if (matlistgui) matlistgui->UpdateMaterialList(); menubar=(guiMenuBar *)paws->FindWidget("menubar"); pslistgui=(guiPSList *)paws->FindWidget("particlesystems"); // resource_manager->LoadLibraryFile("/this/data/partview/libs/test","material_library.xml"); NewParticleSystem("Initial System0",csVector3(0,5,0)); // Initialized ok! return true; } /// The main application runloop void PartViewApp::Run() { // We use the CS runloop entirely csDefaultRunLoop(object_reg); } bool PartViewApp::CreateDefaultRoom() { //// // The room we're creating will be a box from -5, 0 , -5 to 5, 20, 5. // A cube would be harder to distiguish orientation in. // //// // We use a convenience function to create an empty mesh that has certain parameters set appropriately for a bounding box // (the outer walls of the room). This mesh is set to zbuffer fill and draw with the 'wall' priority which ensures it // will be rendered in the correct order. csRef walls (engine->CreateSectorWallsMesh (the_room, "outer_walls")); // CreateSectorWallsMesh creates a mesh using the ambiguously named 'thing' plugin. // Thing meshes and genmeshes are two types of general purpose meshes used in Crystal Space. Each has its own // limitations, but thing meshes are supposed to be more flexible. // Here we use the SCF_QUERY_INTERFACE() macro to safely retrieve the iThingState interface from the meshobject retrieved from the meshwrapper returned above. csRef walls_thingstate = SCF_QUERY_INTERFACE (walls->GetMeshObject (), iThingState); // Now we can use the Thing state to get the factory. Although we have created an instance of a mesh, the mesh has no polygons. // Each instance of a mesh shares its geometry data with all other instances of the same mesh. This data is stored in the 'factory' // which is named such because you can generate new instances from the factory at any time. // For our purposes, we need to add some polygons (the outer walls) so we first have to get access to the factory. csRef walls_state = walls_thingstate->GetFactory (); // iThingFactoryState::AddInsideBox is a convenience function that creates a box with all 6 sides facing inward. // Here we specify the minimum and maximum dimensions. walls_state->AddInsideBox (csVector3 (-5, 0, -5), csVector3 (5, 20, 5)); // We've defined the box, facing inward, but a texture needs to be applied to the surfaces or else we wont really see anything. // Load a texture to apply to the inside of our room // We'll load it from the standard library included with CS in data/standard.zip - which is mounted at /lib/std/ // We'll load a stone texture named stone4.gif and call it 'stone' // In this case we don't want to do anything fancy with the material, so we'll use the form of LoadTexture that creates a material wrapper // for us and registers it automatically. if (!loader->LoadTexture ("stone", "/lib/std/stone4.gif")) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::Initialize()","Error loading '/lib/std/stone4.gif' as texture/material 'stone'"); return false; } // We'll retrieve a pointer to the interface for the material wrapper to assign to the wall polygons iMaterialWrapper* stone_wrapper = engine->GetMaterialList ()->FindByName ("stone"); // The first parameter of iThingFactoryState::SetPolygonMaterial is a range of polygons which will be affected. // CS_POLYRANGE_LAST is a macro encompasing all polygons. walls_state->SetPolygonMaterial (CS_POLYRANGE_LAST, stone_wrapper); // This form of SetPolygonTextureMapping performs implicit mapping of the texture across the polygons. // The method is better described in the interface of iThingFactoryState. Briefly, the texture will // be repeated approximated 3 times over each polygon. walls_state->SetPolygonTextureMapping (CS_POLYRANGE_LAST, 3); // We need some lights to be able to see anything. Add a few: // We'll reuse this for creating each light csRef light; // A lightlist is a simple list of lights. In this case we'll start out with the complete list of // lights in our sector (empty list) and add our lights to that list. // This doesn't actually make the lights affect the objects in the room yet. iLightList* ll = the_room->GetLights (); // Unnamed light, at -3,5,10 with 10 light radius and red color light = engine->CreateLight (0, csVector3 (-3, 5, 0), 10, csColor (1, 0, 0)); ll->Add (light); // Unnamed light, at 3,5,0 with 10 light radius and blue color light = engine->CreateLight (0, csVector3 (3, 5, 0), 10, csColor (0, 0, 1)); ll->Add (light); // Unnamed light, at 0,5,-3 with 10 light radius and green color light = engine->CreateLight (0, csVector3 (0, 5, -3), 10, csColor (0, 1, 0)); ll->Add (light); return true; } bool PartViewApp::LoadMapFileAsRoom(const char *mapfile) { // Not fully implemented yet if (!mapfile) return false; if (strlen(mapfile) > 4 && !strcmp(mapfile+strlen(mapfile)-4,".zip")) { csRef realpath=vfs->GetRealPath(mapfile); vfs->Unmount("/map/",NULL); if (vfs->Mount("/map/",realpath->GetData())) { int i; csRef files; #ifdef _RPTF0 _RPTF0(_CRT_WARN,"Mount succeeded, iterating files...\n"); #endif vfs->ChDir("/map/"); files=vfs->FindFiles("/map/"); for (i=0;iLength();i++) { #ifdef _RPTF1 _RPTF1(_CRT_WARN,"Found file:%s\n",files->Get(i)); #endif } return loader->LoadMapFile("/map/world"); } } return loader->LoadMapFile(mapfile); } PartSystemTracker *PartViewApp::NewParticleSystem(const char *system_name,csVector3 position) { // Create a particle system csRef ps_fact_wrapper = engine->CreateMeshFactory("crystalspace.mesh.object.particles",system_name); if (!ps_fact_wrapper.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::NewParticleSystem()","Could not create an iMeshFactoryWrapper for %s!",system_name); return NULL; } csRef ps_factory = ps_fact_wrapper->GetMeshObjectFactory(); csRef ps_factory_state = SCF_QUERY_INTERFACE(ps_factory,iParticlesFactoryState); iMaterialWrapper* mat_wrapper = engine->GetMaterialList ()->FindByName ("stone"); ps_factory_state->SetMaterial(mat_wrapper); ps_factory_state->SetAutoStart(true); ps_factory_state->SetParticlesPerSecond(15); ps_factory_state->SetPointEmitType(); ps_factory_state->SetEmitTime(1000.0); csRef particle_system = ps_factory->NewInstance(); csRef ps_wrapper = engine->CreateMeshWrapper(particle_system,system_name,the_room,position); PartSystemTracker *ps_track = new PartSystemTracker(ps_wrapper,system_name,ps_fact_wrapper); ps_track->ShowOrientationArrows(true); if (pslistgui) pslistgui->AddParticleSystemInterface(ps_track); if (menubar && pslistgui) menubar->RefreshPSCount(pslistgui->GetParticleSystemCount()); return ps_track; } void PartViewApp::PointFromCenterOfCamera(float distance,csVector3 &world_point) { csRef camera=view->GetCamera(); csVector3 camera_unitclick; if (!camera) { world_point.Set(0.0f,0.0f,0.0f); return; } csVector2 perspective(camera->GetShiftX(),camera->GetShiftY()); camera->InvPerspective(perspective,distance,camera_unitclick); world_point=camera->GetTransform().This2Other(camera_unitclick); } PartSystemTracker *PartViewApp::NewParticleSystemAtCamera(const char *system_name) { csVector3 world_unitclick; PointFromCenterOfCamera(1.0f,world_unitclick); // Create a new particle system 1 unit out from the camera return NewParticleSystem(system_name,world_unitclick); } void PartViewApp::RemoveParticleSystem(PartSystemTracker *system) { if (pslistgui) pslistgui->RemoveParticleSystemInterface(system); delete system; } // // This is a static callback wrapper for the event handler. // // Callbacks must be static, so this uses a global pointer to a single instance of the MainApp class // to redirect events to the class member function. // // bool PartViewApp::StaticEventHandler(iEvent& ev) { // If the pointer is not valid, don't crash if (g_pApp) return g_pApp->EventHandler(ev); else { #ifdef _RPTF0 _RPTF0(_CRT_WARN,"PartViewApp::StaticEventHandler() - Warning! Static PartViewApp::g_pApp is NULL!\n"); #endif return false; } } bool PartViewApp::EventHandler(iEvent &ev) { // Give PAWS the first shot at handling events. if (paws->HandleEvent(ev)) return true; switch(ev.Type) { case csevBroadcast: switch (ev.Command.Code) { case cscmdProcess: // Only spend time drawing if the window is visible if (window_visible) { // cscmdProcess indicates the begining of processing for a frame StartFrame (); } // Return true for handled return true; case cscmdFinalProcess: FinishFrame(); return true; case cscmdPostProcess: { if (window_visible) { // Draw PAWS interface only if the window is visible g3d->BeginDraw(engine->GetBeginDrawFlags() | CSDRAW_2DGRAPHICS); paws->Draw(); } else { csSleep(150); } break; } case cscmdCanvasHidden: // The window was hidden window_visible=false; break; case cscmdCanvasExposed: // The window was made visible window_visible=true; break; } break; case csevMouseDown: switch (ev.Mouse.Button) { case 1: if (!mouse_left_down) { // Start grid selection csVector3 pt,vec; unsigned int x,z; ScreenToWorld(ev.Mouse.x,ev.Mouse.y,vec,pt); // csReport(object_reg, CS_REPORTER_SEVERITY_WARNING,"MainApp - Mouseclick","World coords: (pt)x=%f y=%f z=%f (vec) x=%f y=%f z=%f", // pt.x,pt.y,pt.z,vec.x,vec.y,vec.z); } mouse_left_down=true; break; case 2: if (!mouse_right_down) { // Start height adjustment last_mouseright_y=ev.Mouse.y; } mouse_right_down=true; break; default: break; } break; case csevMouseUp: switch (ev.Mouse.Button) { case 1: if (mouse_left_down) { // End grid selection } mouse_left_down=false; break; case 2: if (mouse_right_down) { // End height adjustment } mouse_right_down=false; break; default: break; } break; case csevMouseMove: if (mouse_left_down) { // Continue grid selection csVector3 pt,vec; unsigned int x,z; ScreenToWorld(ev.Mouse.x,ev.Mouse.y,vec,pt); } if (mouse_right_down) { } break; case csevKeyboard: if (csKeyEventHelper::GetEventType (&ev) == csKeyEventTypeDown && (csKeyEventHelper::GetCookedCode (&ev) == CSKEY_ESC)) { // Handle the ESC key to quit the application csRef q (CS_QUERY_REGISTRY (object_reg, iEventQueue)); if (q) q->GetEventOutlet()->Broadcast (cscmdQuit); // Return true for handled return true; } break; } return false; } // // Drawing occurs in what are called 'frames'. One frame is one image displayed to the screen - usually considered a single point in time // StartFrame() performs setup that needs to be done at the begining of drawing a frame. // FinishFrame() performs steps to complete drawing the frame void PartViewApp::StartFrame () { // First get elapsed time from the virtual clock. csTicks elapsed_time = vc->GetElapsedTicks (); // Perform any timed processing that the app needs. This is done only once per frame // on the assumption that once per frame is the fastest anything is output, so it's likely the most frequently // things will need processing TimedProcessing(elapsed_time); // Now rotate the camera according to keyboard state float speed = (elapsed_time / 1000.0) * (0.06 * 20); iCamera* c = view->GetCamera(); if (kbd->GetKeyState (CSKEY_SHIFT)) { // If the user is holding down shift, the arrow keys will cause // the camera to strafe up, down, left or right from it's // current position. if (kbd->GetKeyState (CSKEY_RIGHT)) c->Move (CS_VEC_RIGHT * 4 * speed); if (kbd->GetKeyState (CSKEY_LEFT)) c->Move (CS_VEC_LEFT * 4 * speed); if (kbd->GetKeyState (CSKEY_UP)) c->Move (CS_VEC_UP * 4 * speed); if (kbd->GetKeyState (CSKEY_DOWN)) c->Move (CS_VEC_DOWN * 4 * speed); } else { // left and right cause the camera to rotate on the global Y // axis; page up and page down cause the camera to rotate on the // _camera's_ X axis (more on this in a second) and up and down // arrows cause the camera to go forwards and backwards. if (kbd->GetKeyState (CSKEY_RIGHT)) rotY += speed; if (kbd->GetKeyState (CSKEY_LEFT)) rotY -= speed; if (kbd->GetKeyState (CSKEY_PGUP)) rotX += speed; if (kbd->GetKeyState (CSKEY_PGDN)) rotX -= speed; if (kbd->GetKeyState (CSKEY_UP)) c->Move (CS_VEC_FORWARD * 4 * speed); if (kbd->GetKeyState (CSKEY_DOWN)) c->Move (CS_VEC_BACKWARD * 4 * speed); } // We now assign a new rotation transformation to the camera. You // can think of the rotation this way: starting from the zero // position, you first rotate "rotY" radians on your Y axis to get // the first rotation. From there you rotate "rotX" radians on the // your X axis to get the final rotation. We multiply the // individual rotations on each axis together to get a single // rotation matrix. The rotations are applied in right to left // order . csMatrix3 rot = csXRotMatrix3 (rotX) * csYRotMatrix3 (rotY); csOrthoTransform ot (rot, c->GetTransform().GetOrigin ()); c->SetTransform (ot); // Tell 3D driver we're going to display 3D things. if (!g3d->BeginDraw (engine->GetBeginDrawFlags () | CSDRAW_3DGRAPHICS)) return; // Tell the camera to render into the frame buffer. view->Draw (); } void PartViewApp::FinishFrame () { // Tell the 3d rendering layer we are done drawing g3d->FinishDraw (); // And tell it to put the total results of drawing out to the screen g3d->Print (0); } bool PartViewApp::RegisterPawsFactories() { pawsWidgetFactory* factory; // register the factories of all other custom made paws widgets here factory = new guiMenuBarFactory(paws); factory = new guiMaterialListFactory(paws); factory = new pawsScrollPaneFactory(paws); factory = new pawsCollapsableWidgetFactory(paws); factory = new guiParticleSystemFactory(paws); factory = new guiPSListFactory(paws); factory = new guiColorRowFactory(paws); return true; } bool PartViewApp::LoadPawsWidgets() { bool success=true; success=success & TryLoadPawsWidget("data/partview/menubar.xml"); success=success & TryLoadPawsWidget("data/partview/materiallist.xml"); success=success & TryLoadPawsWidget("data/partview/pslist.xml"); // load all other custom made paws widgets here return success; } bool PartViewApp::TryLoadPawsWidget(const char *xml_filename) { if (!paws->LoadWidget(xml_filename)) { csReport (object_reg, CS_REPORTER_SEVERITY_ERROR,"PartViewApp::TryLoadPawsWidget()","Error loading widget '%s'",xml_filename); return false; } return true; } void PartViewApp::ScreenToWorld(int x, int y,csVector3 &click_vector,csVector3 &camerapos) { // Converts the location of the mouse pointer into a point and vector in world space csRef camera=view->GetCamera(); csVector3 camera_unitclick,world_unitclick; if (!camera.IsValid()) return; csVector2 perspective(x,camera->GetShiftY()*2-y); camera->InvPerspective(perspective,1.0f,camera_unitclick); world_unitclick=camera->GetTransform().This2Other(camera_unitclick); camerapos=camera->GetTransform().GetO2TTranslation(); click_vector=world_unitclick - camerapos; } void PartViewApp::TimedProcessing(csTicks elapsed) { // Check the paws GUI for outstanding load or save requests if need be // if (gui_menu_widget) // gui_menu_widget->ProcessTimedEvents(elapsed); // if (broadgui) // broadgui->MatchSelectedSystemRunningState(); if (matlistgui) matlistgui->DoTimedChecks(); if (menubar) menubar->DoTimedChecks(); if (pslistgui) pslistgui->DoTimedChecks(elapsed); } bool PartViewApp::LoadParticleSystem(const char *filename) { csRef ps_file; csRef ps_document; csRef ps_rootnode,ps_meshfactnode,meshfact_pluginnode,ps_params; csRef ps_nodeit,ps_paramit; int loaded_systems=0; csString system_name; static int global_load_count=0; if (!particlesloader) return false; ps_file=vfs->Open(filename,VFS_FILE_READ); if (!ps_file) { // TODO: Display a notice about failure return false; } csRef docsys (CS_QUERY_REGISTRY(object_reg, iDocumentSystem)); if (!docsys.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iDocumentSystem interface in the available plugins!"); return false; } ps_document=docsys->CreateDocument(); ps_document->Parse(ps_file); ps_rootnode=ps_document->GetRoot(); ps_nodeit=ps_rootnode->GetNodes("meshfact"); ps_nodeit=ps_rootnode->GetNodes("meshfact"); while (ps_nodeit->HasNext()) { ps_meshfactnode=ps_nodeit->Next(); meshfact_pluginnode=ps_meshfactnode->GetNode("plugin"); // No plugin specified if (!meshfact_pluginnode) continue; // Not using the plugin we support if (!meshfact_pluginnode->GetContentsValue() || strcmp("crystalspace.mesh.loader.factory.particles",meshfact_pluginnode->GetContentsValue())) continue; csRef attrib=ps_meshfactnode->GetAttribute("name"); if (attrib) system_name=attrib->GetValue(); else system_name.Format("Loaded System%d",global_load_count++); ps_params=ps_meshfactnode->GetNode("params"); if (!ps_params) continue; csRef ldr_context = engine->CreateLoaderContext(); csRef fact_ibase=particlesloader->Parse(ps_params,ldr_context,NULL); if (!fact_ibase) continue; csRef ps_fact = SCF_QUERY_INTERFACE(fact_ibase,iMeshObjectFactory); if (!ps_fact) continue; csRef ps_fact_wrapper = engine->CreateMeshFactory(ps_fact,system_name); if (!ps_fact_wrapper) continue; csRef ps_factory = ps_fact_wrapper->GetMeshObjectFactory(); csRef ps_factory_state = SCF_QUERY_INTERFACE(ps_factory,iParticlesFactoryState); csRef particle_system = ps_factory->NewInstance(); if (!particle_system->GetMaterialWrapper()) { // Factory did not load a default material, assign one iMaterialWrapper* mat_wrapper = engine->GetMaterialList ()->FindByName ("stone"); ps_factory_state->SetMaterial(mat_wrapper); particle_system->SetMaterialWrapper(mat_wrapper); } csVector3 position; PointFromCenterOfCamera(1.0f,position); csRef ps_wrapper = engine->CreateMeshWrapper(particle_system,system_name,the_room,position); PartSystemTracker *ps_track = new PartSystemTracker(ps_wrapper,system_name,ps_fact_wrapper); ps_track->ShowOrientationArrows(true); if (pslistgui) pslistgui->AddParticleSystemInterface(ps_track); loaded_systems++; } if (loaded_systems>0) { if (menubar && pslistgui) menubar->RefreshPSCount(pslistgui->GetParticleSystemCount()); return true; } return false; } bool PartViewApp::SaveParticleSystem(PartSystemTracker *ps_track, const char *filename) { // TODO: vfs->Exists() confirm popup csRef ps_file; csRef ps_document; csRef ps_rootnode,ps_meshfactnode,meshfact_pluginnode,ps_params,work_node,node_text; csRef ps_nodeit,ps_paramit; iMeshObject *ps_meshobj; csRef ps_obj_state; if (!ps_track) return false; ps_meshobj=ps_track->particle_system_wrapper->GetMeshObject(); if (!ps_meshobj) return false; ps_obj_state=SCF_QUERY_INTERFACE(ps_meshobj,iParticlesObjectState); if (!ps_obj_state) return false; ps_file=vfs->Open(filename,VFS_FILE_WRITE); if (!ps_file) { // TODO: Display a notice about failure return false; } csRef docsys (CS_QUERY_REGISTRY(object_reg, iDocumentSystem)); if (!docsys.IsValid()) { csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "PartViewApp::Initialize()","Could not find an iDocumentSystem interface in the available plugins!"); return false; } ps_document=docsys->CreateDocument(); ps_rootnode=ps_document->CreateRoot(); if (!ps_rootnode) return false; ps_meshfactnode=ps_rootnode->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!ps_meshfactnode) return false; ps_meshfactnode->SetValue("meshfact"); ps_meshfactnode->SetAttribute("name",ps_track->name); meshfact_pluginnode=ps_meshfactnode->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!meshfact_pluginnode) return false; meshfact_pluginnode->SetValue("plugin"); work_node=meshfact_pluginnode->CreateNodeBefore(CS_NODE_TEXT,0); if (!work_node) return false; work_node->SetValue("crystalspace.mesh.loader.factory.particles"); ps_params=ps_meshfactnode->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!ps_params) return false; ps_params->SetValue("params"); // Write emitter { csRef node_emit,node_force; node_emit=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!node_emit) return false; node_emit->SetValue("emitter"); switch (ps_obj_state->GetEmitType()) { case CS_PART_EMIT_SPHERE: node_emit->SetAttribute("type","sphere"); // time work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("time"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetEmitTime()); // innerradius work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("innerradius"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetSphereEmitInnerRadius()); // outerradius work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("outerradius"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetSphereEmitOuterRadius()); break; case CS_PART_EMIT_PLANE: node_emit->SetAttribute("type","plane"); // time work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("time"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetEmitTime()); // size work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("size"); work_node->SetAttributeAsFloat("x",ps_obj_state->GetEmitXSize()); work_node->SetAttributeAsFloat("y",ps_obj_state->GetEmitYSize()); break; case CS_PART_EMIT_BOX: node_emit->SetAttribute("type","box"); // time work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("time"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetEmitTime()); // size work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("size"); work_node->SetAttributeAsFloat("x",ps_obj_state->GetEmitXSize()); work_node->SetAttributeAsFloat("y",ps_obj_state->GetEmitYSize()); work_node->SetAttributeAsFloat("z",ps_obj_state->GetEmitZSize()); break; case CS_PART_EMIT_CYLINDER: node_emit->SetAttribute("type","cylinder"); // time work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("time"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetEmitTime()); // size work_node=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("size"); // x_size and y_size are used for radius and height work_node->SetAttributeAsFloat("x",ps_obj_state->GetEmitXSize()); work_node->SetAttributeAsFloat("y",ps_obj_state->GetEmitYSize()); break; default: // Unsupported emitter type return false; break; } // Write force csParticleFalloffType falloff_force,falloff_cone; ps_obj_state->GetFalloffType(falloff_force,falloff_cone); node_force=node_emit->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!node_force) return false; // Force amount work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("amount"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetForce()); // range work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("range"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetForceRange()); // Falloff work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("falloff"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; switch (falloff_force) { case CS_PART_FALLOFF_CONSTANT: node_text->SetValue("constant"); break; case CS_PART_FALLOFF_LINEAR: node_text->SetValue("linear"); break; case CS_PART_FALLOFF_PARABOLIC: node_text->SetValue("parabolic"); break; default: return false; break; } node_force->SetValue("force"); switch (ps_obj_state->GetForceType()) { case CS_PART_FORCE_RADIAL: node_force->SetAttribute("type","radial"); // No additional properties break; case CS_PART_FORCE_LINEAR: { csVector3 direction; node_force->SetAttribute("type","linear"); ps_obj_state->GetForceDirection(direction); work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("direction"); work_node->SetAttributeAsFloat("x",direction.x); work_node->SetAttributeAsFloat("y",direction.y); work_node->SetAttributeAsFloat("z",direction.z); } break; case CS_PART_FORCE_CONE: { csVector3 direction; node_force->SetAttribute("type","cone"); ps_obj_state->GetForceDirection(direction); work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("direction"); work_node->SetAttributeAsFloat("x",direction.x); work_node->SetAttributeAsFloat("y",direction.y); work_node->SetAttributeAsFloat("z",direction.z); work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("coneradius"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetForceConeRadius()); work_node=node_force->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("conefalloff"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; switch (falloff_cone) { case CS_PART_FALLOFF_CONSTANT: node_text->SetValue("constant"); break; case CS_PART_FALLOFF_LINEAR: node_text->SetValue("linear"); break; case CS_PART_FALLOFF_PARABOLIC: node_text->SetValue("parabolic"); break; default: return false; break; } } break; default: // Unsupported force type return false; break; } // Force done } // Emitter done // dampener work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("dampener"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetDampener()); // mass work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("mass"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetMass()); // massvariation work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("massvariation"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetMassVariation()); // particles per second work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("pps"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsInt(ps_obj_state->GetParticlesPerSecond()); // initial particles work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("initial"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsInt(ps_obj_state->GetInitialParticleCount()); // gravity { csVector3 gravity; ps_obj_state->GetGravity(gravity); work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("gravity"); work_node->SetAttributeAsFloat("x",gravity.x); work_node->SetAttributeAsFloat("y",gravity.y); work_node->SetAttributeAsFloat("z",gravity.z); } // diffusion work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("diffusion"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetDiffusion()); // particle radius work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("radius"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetParticleRadius()); // particle lifetime work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("ttl"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetTimeToLive()); // particle lifetime variation work_node=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("timevariation"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetTimeVariation()); // Color method { csRef node_color; node_color=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!node_color) return false; node_color->SetValue("colormethod"); switch (ps_obj_state->GetParticleColorMethod()) { case CS_PART_COLOR_CONSTANT: { csColor4 color; ps_obj_state->GetConstantColor(color); node_color->SetAttribute("type","constant"); work_node=node_color->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("color"); work_node->SetAttributeAsFloat("red",color.red); work_node->SetAttributeAsFloat("green",color.green); work_node->SetAttributeAsFloat("blue",color.blue); } break; case CS_PART_COLOR_LINEAR: { csRef node_gradient; int c_i,c_l; csArray gradient_colors=ps_obj_state->GetGradient(); c_l=gradient_colors.Length(); node_color->SetAttribute("type","linear"); node_gradient=node_color->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!node_gradient) return false; node_gradient->SetValue("gradient"); for (c_i=0;c_iCreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("color"); work_node->SetAttributeAsFloat("red",gradient_colors[c_i].red); work_node->SetAttributeAsFloat("green",gradient_colors[c_i].green); work_node->SetAttributeAsFloat("blue",gradient_colors[c_i].blue); } } break; case CS_PART_COLOR_LOOPING: { csRef node_gradient; int c_i,c_l; csArray gradient_colors=ps_obj_state->GetGradient(); c_l=gradient_colors.Length(); node_color->SetAttribute("type","looping"); work_node->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetColorLoopTime()); node_gradient=node_color->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!node_gradient) return false; node_gradient->SetValue("gradient"); for (c_i=0;c_iCreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("color"); work_node->SetAttributeAsFloat("red",gradient_colors[c_i].red); work_node->SetAttributeAsFloat("green",gradient_colors[c_i].green); work_node->SetAttributeAsFloat("blue",gradient_colors[c_i].blue); } } break; case CS_PART_COLOR_HEAT: node_color->SetAttribute("type","heat"); work_node=node_color->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!work_node) return false; work_node->SetValue("temp"); node_text=work_node->CreateNodeBefore(CS_NODE_TEXT,0); if (!node_text) return false; node_text->SetValueAsFloat(ps_obj_state->GetBaseHeat()); break; default: // Cannot save callback color methods... how did you set a callback in this app anyway?! return false; break; } } // Color Method done // Material selection { iObject *mat_obj; iMeshObject *ps_obj; iMaterialWrapper *ps_mat_wrapper; const char *mat_name; csRef node_material; node_material=ps_params->CreateNodeBefore(CS_NODE_ELEMENT,0); if (!node_material) return false; node_material->SetValue("material"); ps_obj=ps_track->particle_system_wrapper->GetMeshObject(); if (!ps_obj) return false; ps_mat_wrapper=ps_obj->GetMaterialWrapper(); if (!ps_mat_wrapper) return false; mat_obj=ps_mat_wrapper->QueryObject(); if (!mat_obj) return false; mat_name=mat_obj->GetName(); if (!mat_name) return false; work_node=node_material->CreateNodeBefore(CS_NODE_TEXT,0); if (!work_node) return false; work_node->SetValue(mat_name); } return (ps_document->Write(ps_file)==0); } PartSystemTracker::PartSystemTracker(csRef psystem_wrapper,const char *pname,csRef psfactory) : name(pname), particle_system_wrapper(psystem_wrapper), ps_factory_wrapper(psfactory) { system_stopping=false; show_arrows=false; orientation_arrows=NULL; } PartSystemTracker::~PartSystemTracker() { csRef engine = CS_QUERY_REGISTRY (PartViewApp::g_pApp->object_reg, iEngine); if (engine) { engine->RemoveObject(particle_system_wrapper); engine->RemoveObject(ps_factory_wrapper); } particle_system_wrapper=NULL; ps_factory_wrapper=NULL; delete orientation_arrows; } void PartSystemTracker::ShowOrientationArrows(bool show) { if (!particle_system_wrapper) return; if (!orientation_arrows) { iMovable *movable; iSector *existing_sector; iSectorList *sec_list; csVector3 system_pos; csVector3 x_vec,y_vec; csReversibleTransform movable_trans; csMatrix3 t2o; movable=particle_system_wrapper->GetMovable(); if (!movable) return; sec_list=movable->GetSectors(); if (sec_list->GetCount() < 1) return; existing_sector=sec_list->Get(0); system_pos=movable->GetPosition(); movable_trans=movable->GetTransform(); t2o=movable_trans.GetT2O(); x_vec=t2o.Col1(); y_vec=t2o.Col2(); orientation_arrows=new CoordinateArrows(PartViewApp::g_pApp->object_reg,existing_sector,system_pos,y_vec,x_vec,0.5f,0.2f); if (!orientation_arrows || !orientation_arrows->Initialize()) return; movable->AddListener(orientation_arrows); } if (show) orientation_arrows->Show(); else orientation_arrows->Hide(); show_arrows=show; } bool PartSystemTracker::OrientationArrowsVisible() { return show_arrows; }