Hello,

I want to display something like a path of an moving object. I currently use a genmesh consisting of an triangle strip. Every time the object moves I manipulate the factoryState (vertices, normals, texels, triangles) to represent the new path and calling Invalidate() to announce the changes.

This works partially as the genmesh representing the path has the correct geometry, but it becomes black, has random colors or flickers in color.

It looks like genmesh doesn't react well to changes in vertex/triangle count. How do I animate a mesh with changing vertex count correctly?

I'm using CrystalSpace version 1.0 from SVN on Windows XP with VS 2005.

Attached you find the source of a modified simple1 tutorial to show the problem. The genmesh manipulation is done in UpdateMesh().


Thanks,
Philipp
/*
    Copyright (C) 2001 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "simple1.h"
#include <vector>

CS_IMPLEMENT_APPLICATION

//---------------------------------------------------------------------------

Simple::Simple ()
{
  SetApplicationName ("CrystalSpace.Simple1");
}

Simple::~Simple ()
{
}

void Simple::Frame ()
{
  // First get elapsed time from the virtual clock.
  csTicks elapsed_time = vc->GetElapsedTicks ();
  // 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);

  meshPoints = 2 + (vc->GetCurrentTicks() / 100) % 100;
  UpdateMesh(meshPoints);
}

bool Simple::OnKeyboard(iEvent& ev)
{
  // We got a keyboard event.
  csKeyEventType eventtype = csKeyEventHelper::GetEventType(&ev);
  if (eventtype == csKeyEventTypeDown)
  {
    // The user pressed a key (as opposed to releasing it).
    utf32_char code = csKeyEventHelper::GetCookedCode(&ev);
    if (code == CSKEY_ESC)
    {
      // The user pressed escape to exit the application.
      // The proper way to quit a Crystal Space application
      // is by broadcasting a csevQuit event. That will cause the
      // main runloop to stop. To do that we get the event queue from
      // the object registry and then post the event.
      csRef<iEventQueue> q = 
        csQueryRegistry<iEventQueue> (GetObjectRegistry());
      if (q.IsValid()) q->GetEventOutlet()->Broadcast(
        csevQuit(GetObjectRegistry()));
    }
  }
  return false;
}

bool Simple::OnInitialize(int /*argc*/, char* /*argv*/ [])
{
  // RequestPlugins() will load all plugins we specify. In addition
  // it will also check if there are plugins that need to be loaded
  // from the config system (both the application config and CS or
  // global configs). In addition it also supports specifying plugins
  // on the commandline.
  if (!csInitializer::RequestPlugins(GetObjectRegistry(),
    CS_REQUEST_VFS,
    CS_REQUEST_OPENGL3D,
    CS_REQUEST_ENGINE,
    CS_REQUEST_FONTSERVER,
    CS_REQUEST_IMAGELOADER,
    CS_REQUEST_LEVELLOADER,
    CS_REQUEST_REPORTER,
    CS_REQUEST_REPORTERLISTENER,
    CS_REQUEST_END))
    return ReportError("Failed to initialize plugins!");

  // "Warm up" the event handler so it can interact with the world
  csBaseEventHandler::Initialize(GetObjectRegistry());

  // Now we need to register the event handler for our application.
  // Crystal Space is fully event-driven. Everything (except for this
  // initialization) happens in an event.
  // Rather than simply handling all events, we subscribe to the
  // particular events we're interested in.
  csEventID events[] = {
    csevFrame (GetObjectRegistry()),
    csevKeyboardEvent (GetObjectRegistry()),
    CS_EVENTLIST_END
  };
  if (!RegisterQueue(GetObjectRegistry(), events))
    return ReportError("Failed to set up event handler!");

  // Report success
  return true;
}

void Simple::OnExit()
{
  // Shut down the event handlers we spawned earlier.
  drawer.Invalidate();
  printer.Invalidate();
}

bool Simple::Application()
{
  // Open the main system. This will open all the previously loaded plug-ins.
  // i.e. all windows will be opened.
  if (!OpenApplication(GetObjectRegistry()))
    return ReportError("Error opening system!");

  if (SetupModules()) {
    // This calls the default runloop. This will basically just keep
    // broadcasting process events to keep the game going.
    Run();
  }

  return true;
}

bool Simple::SetupModules ()
{
  // Now get the pointer to various modules we need. We fetch them
  // from the object registry. The RequestPlugins() call we did earlier
  // registered all loaded plugins with the object registry.
  g3d = csQueryRegistry<iGraphics3D> (GetObjectRegistry());
  if (!g3d) return ReportError("Failed to locate 3D renderer!");

  engine = csQueryRegistry<iEngine> (GetObjectRegistry());
  if (!engine) return ReportError("Failed to locate 3D engine!");

  vc = csQueryRegistry<iVirtualClock> (GetObjectRegistry());
  if (!vc) return ReportError("Failed to locate Virtual Clock!");

  kbd = csQueryRegistry<iKeyboardDriver> (GetObjectRegistry());
  if (!kbd) return ReportError("Failed to locate Keyboard Driver!");

  loader = csQueryRegistry<iLoader> (GetObjectRegistry());
  if (!loader) return ReportError("Failed to locate Loader!");

  // We need a View to the virtual world.
  view.AttachNew(new csView (engine, g3d));
  iGraphics2D* g2d = g3d->GetDriver2D ();
  // We use the full window to draw the world.
  view->SetRectangle (0, 0, g2d->GetWidth (), g2d->GetHeight ());

  // First disable the lighting cache. Our app is simple enough
  // not to need this.
  engine->SetLightingCacheMode (0);

  // Here we create our world.
  CreateRoom();

  // Let the engine prepare all lightmaps for use and also free all images 
  // that were loaded for the texture manager.
  engine->Prepare ();

  // these are used store the current orientation of the camera
  rotY = rotX = 0;
  
  // Now we need to position the camera in our world.
  view->GetCamera ()->SetSector (room);
  view->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3));

  // We use some other "helper" event handlers to handle 
  // pushing our work into the 3D engine and rendering it
  // to the screen.
  drawer.AttachNew(new FrameBegin3DDraw (GetObjectRegistry (), view));
  printer.AttachNew(new FramePrinter (GetObjectRegistry ()));

  return true;
}

void Simple::CreateRoom ()
{
  // Load the texture from the standard library.  This is located in
  // CS/data/standard.zip and mounted as /lib/std using the Virtual
  // File System (VFS) plugin.
  if (!loader->LoadTexture ("stone", "/lib/std/stone4.gif"))
    ReportError("Error loading 'stone4' texture!");

  iMaterialWrapper* tm = engine->GetMaterialList ()->FindByName ("stone");

  // We create a new sector called "room".
  room = engine->CreateSector ("room");

  // Creating the walls for our room.
  csRef<iMeshWrapper> walls (engine->CreateSectorWallsMesh (room, "walls"));
  iMeshObject* walls_object = walls->GetMeshObject ();
  iMeshObjectFactory* walls_factory = walls_object->GetFactory();
  csRef<iThingFactoryState> walls_state = 
    scfQueryInterface<iThingFactoryState> (walls_factory);
  walls_state->AddInsideBox (csVector3 (-5, 0, -5), csVector3 (5, 20, 5));
  walls_state->SetPolygonMaterial (CS_POLYRANGE_LAST, tm);
  walls_state->SetPolygonTextureMapping (CS_POLYRANGE_LAST, 3);

  // Now we need light to see something.
  csRef<iLight> light;
  iLightList* ll = room->GetLights ();

  light = engine->CreateLight(0, csVector3(-3, 5, 0), 10, csColor(1, 0, 0));
  ll->Add (light);

  light = engine->CreateLight(0, csVector3(3, 5,  0), 10, csColor(0, 0, 1));
  ll->Add (light);

  light = engine->CreateLight(0, csVector3(0, 5, -3), 10, csColor(0, 1, 0));
  ll->Add (light);


    meshFactoryWrapper    = 
engine->CreateMeshFactory("crystalspace.mesh.object.genmesh", NULL);
    csRef<iGeneralFactoryState> factoryState    = 
SCF_QUERY_INTERFACE(meshFactoryWrapper->GetMeshObjectFactory(), 
iGeneralFactoryState);
    meshFactoryWrapper->GetMeshObjectFactory()->SetMaterialWrapper(tm);
    factoryState->SetColor(csColor(1.0, 1.0, 1.0));

    meshPoints  = 5;
    UpdateMesh(meshPoints);

    meshWrapper           = engine->CreateMeshWrapper(meshFactoryWrapper, NULL, 
room);
    meshWrapper->SetRenderPriority(engine->GetObjectRenderPriority());
    meshWrapper->SetZBufMode(CS_ZBUF_USE);

    csRef<iGeneralMeshState>    meshState   = 
SCF_QUERY_INTERFACE(meshWrapper->GetMeshObject(), iGeneralMeshState);

    meshState->SetLighting(true);
    meshState->SetManualColors(false);
}

void Simple::UpdateMesh(int n)
{
    csRef<iGeneralFactoryState> factoryState    = 
SCF_QUERY_INTERFACE(meshFactoryWrapper->GetMeshObjectFactory(), 
iGeneralFactoryState);

    std::vector<csVector3>        points;

    // Funktion mit diskreten Werten aufrufen, im Intervall von 'start' bis 
'stop'
    for (int i = 0; i < n; i++)
    {
        points.push_back(csVector3(1*sin(i*0.1), 5 + i*0.01, 1*cos(i*0.1)));
    }

    bool    doublesided    = true;
    int     pointscount    = (int)points.size();
    double  width          = 0.1;

    factoryState->SetVertexCount(pointscount * (doublesided ? 4 : 2));
    factoryState->SetTriangleCount((pointscount - 1) * (doublesided ? 4 : 2));
    

    csVector3*  vertices    = factoryState->GetVertices();
    csVector3*  normals     = factoryState->GetNormals();
    csVector2*  uv          = factoryState->GetTexels();
    csTriangle* triangles   = factoryState->GetTriangles();

    for (int i = 0; i < pointscount; i++)
    {
        int     k   = 2 * i;
        int     d   = 2 * (i - 1);
        csVector3 up(0,1,0);
        csVector3 t;
        csVector3 v;

        if (i == 0)
                t   = (points[i+1] - points[i]);
        else
                t   = (points[i] - points[i-1]);
        v.Cross(up, t);
        v.Normalize();
        v *= width/2;

        csVector3 a = points[i] + v;
        csVector3 b = points[i] - v;

        vertices[k+0].Set(a);
        vertices[k+1].Set(b);

        normals[k+0].Set(0, 1, 0);
        normals[k+1].Set(0, 1, 0);

        if ((i & 1) == 0)
        {
            uv[k+0].Set(0, 0);
            uv[k+1].Set(1, 0);
        }
        else
        {
            uv[k+0].Set(0, 1);
            uv[k+1].Set(1, 1);
        }

        if (i > 0)
        {
            triangles[d+0].Set(k-1, k+1, k+0);
            triangles[d+1].Set(k-2, k-1, k+0);
        }

        if (doublesided)
        {
            int kr  = 2 * pointscount + k;
            int dr  = 2 * (pointscount - 1) + d;

            vertices[kr+0] = vertices[k+0];
            vertices[kr+1] = vertices[k+1];

            normals[kr+0].Set(0, -1, 0);
            normals[kr+1].Set(0, -1, 0);

            uv[kr+0] = uv[k+0];
            uv[kr+1] = uv[k+1];

            if (i > 0)
            {
                triangles[dr+0].Set(k-1, k+0, k+1);
                triangles[dr+1].Set(k-2, k+0, k-1);
            }
        }

    }
}

/*-------------------------------------------------------------------------*
 * Main function
 *-------------------------------------------------------------------------*/
int main (int argc, char* argv[])
{
  /* Runs the application. 
   *
   * csApplicationRunner<> is a small wrapper to support "restartable" 
   * applications (ie where CS needs to be completely shut down and loaded 
   * again). Simple1 does not use that functionality itself, however, it
   * allows you to later use "Simple.Restart();" and it'll just work.
   */
  return csApplicationRunner<Simple>::Run (argc, argv);
}
/*
    Copyright (C) 2001 by Jorrit Tyberghein

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __SIMPLE1_H__
#define __SIMPLE1_H__

#include <crystalspace.h>

/**
 * This is the main class of this Tutorial. It contains the
 * basic initialization code and the main event handler.
 *
 * csApplicationFramework provides a handy object-oriented wrapper around the
 * Crystal Space initialization and start-up functions.
 *
 * csBaseEventHandler provides a base object which does absolutely nothing
 * with the events that are sent to it.
 */
class Simple : public csApplicationFramework, public csBaseEventHandler
{
 private:
  /// A pointer to the 3D engine.
  csRef<iEngine> engine;
   
  /// A pointer to the map loader plugin.
  csRef<iLoader> loader;
     
  /// A pointer to the 3D renderer plugin.
  csRef<iGraphics3D> g3d;
        
  /// A pointer to the keyboard driver.
  csRef<iKeyboardDriver> kbd;
          
  /// A pointer to the virtual clock.
  csRef<iVirtualClock> vc;

  /// A pointer to the view which contains the camera.
  csRef<iView> view;

  /// A pointer to the sector the camera will be in.
  iSector* room;

  /// Current orientation of the camera.
  float rotX, rotY;

  /// Event handlers to draw and print the 3D canvas on each frame
  csRef<FrameBegin3DDraw> drawer;
  csRef<FramePrinter> printer;

  csRef<iMeshFactoryWrapper>    meshFactoryWrapper;
  csRef<iMeshWrapper>           meshWrapper;

  int                           meshPoints;


 public:
  bool SetupModules ();

  /**
   * Handle keyboard events - ie key presses and releases.
   * This routine is called from the event handler in response to a 
   * csevKeyboard event.
   */
  bool OnKeyboard (iEvent&);
  
  /**
   * Setup everything that needs to be rendered on screen. This routine
   * is called from the event handler in response to a csevFrame
   * message, and is called in the "logic" phase (meaning that all
   * event handlers for 3D, 2D, Console, Debug, and Frame phases
   * will be called after this one).
   */
  void Frame ();
  
  /// Here we will create our little, simple world.
  void CreateRoom ();
    
  void UpdateMesh(int n);

  /// Construct our game. This will just set the application ID for now.
  Simple ();

  /// Destructor.
  ~Simple ();

  /// Final cleanup.
  void OnExit ();

  /**
   * Main initialization routine. This routine will set up some basic stuff
   * (like load all needed plugins, setup the event handler, ...).
   * In case of failure this routine will return false. You can assume
   * that the error message has been reported to the user.
   */
  bool OnInitialize (int argc, char* argv[]);

  /**
   * Run the application.
   * First, there are some more initialization (everything that is needed 
   * by Simple1 to use Crystal Space), then this routine fires up the main
   * event loop. This is where everything starts. This loop will  basically
   * start firing events which actually causes Crystal Space to function.
   * Only when the program exits this function will return.
   */
  bool Application ();
  
  /* Declare the name by which this class is identified to the event scheduler.
   * Declare that we want to receive the frame event in the "LOGIC" phase,
   * and that we're not terribly interested in having other events
   * delivered to us before or after other modules, plugins, etc. */
  CS_EVENTHANDLER_PHASE_LOGIC("application.simple1")
};

#endif // __SIMPLE1_H__
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Crystal-main mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/crystal-main
Unsubscribe: mailto:[EMAIL PROTECTED]

Reply via email to