Hello,
I posted some days ago about this problem:
When I modify vertex and triangle information of a genmeshfactory I get
some strange behavior. It looks like vertex colors are totally random,
even if set to fixed values.
To demonstrate this I have modified the simple1 tutorial. Could someone
look at it and check if I made an error in creating or updating the
factory or if CS has some bug here?
I have tested it with pseudo stable release from 3 of September and with
CVS snapshot from 12 and 21 of November, all the same effect. It worked
fine with a snapshot from December of last year.
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"
CS_IMPLEMENT_APPLICATION
//---------------------------------------------------------------------------
Simple::Simple ()
{
SetApplicationName ("CrystalSpace.Simple1");
}
Simple::~Simple ()
{
}
void Simple::ProcessFrame ()
{
// 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);
csRef<iGeneralFactoryState> factoryState =
SCF_QUERY_INTERFACE(meshFactoryWrapper->GetMeshObjectFactory(),
iGeneralFactoryState);
int poincount = (vc->GetCurrentTicks() / 1000) % 10 + 1;
factoryState->SetVertexCount(poincount * 2);
factoryState->SetTriangleCount((poincount - 1) * 2);
csVector3* vertices = factoryState->GetVertices();
csVector3* normals = factoryState->GetNormals();
csVector2* uvs = factoryState->GetTexels();
csTriangle* triangles = factoryState->GetTriangles();
csColor4* colors = factoryState->GetColors();
for (int i = 0; i < poincount; i++)
{
int k = 2 * i;
int d = 2 * (i - 1);
vertices[k+0].Set(1, 1, i/3.0);
vertices[k+1].Set(-1, 1, i/3.0);
normals[k+0].Set(0, 1, 0);
normals[k+1].Set(0, 1, 0);
if ((i & 1) == 0)
{
uvs[k+0].Set(0, 0);
uvs[k+1].Set(1, 0);
}
else
{
uvs[k+0].Set(0, 1);
uvs[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);
}
colors[k+0] = csColor(1, 1, 1);
colors[k+1] = csColor(1, 1, 1);
}
// 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 Simple::FinishFrame ()
{
// Just tell the 3D renderer that everything has been rendered.
g3d->FinishDraw ();
g3d->Print (0);
}
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 cscmdQuit 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(cscmdQuit);
}
}
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!");
// Now we need to setup an event handler for our application.
// Crystal Space is fully event-driven. Everything (except for this
// initialization) happens in an event.
if (!RegisterQueue(GetObjectRegistry()))
return ReportError("Failed to set up event handler!");
return true;
}
void Simple::OnExit()
{
}
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!");
// 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));
meshFactoryWrapper =
engine->CreateMeshFactory("crystalspace.mesh.object.genmesh", NULL);
meshWrapper = engine->CreateMeshWrapper(meshFactoryWrapper, NULL,
room);
meshWrapper->SetRenderPriority(engine->GetObjectRenderPriority());
meshWrapper->SetZBufMode(CS_ZBUF_USE);
meshWrapper->GetFlags().Set(CS_ENTITY_NOLIGHTING);
iMaterialWrapper* tm = engine->GetMaterialList()->FindByName ("stone");
csRef<iGeneralMeshState> meshState =
SCF_QUERY_INTERFACE(meshWrapper->GetMeshObject(), iGeneralMeshState);
meshState->SetMaterialWrapper(tm);
//meshState->SetColor(csColor(1.0, 1.0, 1.0));
meshState->SetManualColors(true);
// This calls the default runloop. This will basically just keep
// broadcasting process events to keep the game going.
Run();
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"));
csRef<iThingState> ws =
SCF_QUERY_INTERFACE (walls->GetMeshObject (), iThingState);
csRef<iThingFactoryState> walls_state = ws->GetFactory ();
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);
}
/*-------------------------------------------------------------------------*
* 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;
csRef<iMeshFactoryWrapper> meshFactoryWrapper;
csRef<iMeshWrapper> meshWrapper;
/**
* 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 cscmdProcess
* broadcast message.
*/
void ProcessFrame ();
/**
* Finally render the screen. This routine is called from the event
* handler in response to a cscmdFinalProcess broadcast message.
*/
void FinishFrame ();
/// Here we will create our little, simple world.
void CreateRoom ();
public:
/// 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 ();
};
#endif // __SIMPLE1_H__