Crystal Space
Welcome, Guest. Please login or register.
September 03, 2014, 02:02:10 am

Login with username, password and session length
Search:     Advanced search
9009 Posts in 2043 Topics by 8379 Members
Latest Member: Hamlock3
* Home Help Search Login Register
+  Crystal Space
|-+  Crystal Space Development
| |-+  Support
| | |-+  [SOLVED] Clicking on Objects
« previous next »
Pages: [1] Print
Author Topic: [SOLVED] Clicking on Objects  (Read 1713 times)
Hannofcart
Newbie
*
Posts: 14


View Profile Email
« on: January 18, 2009, 11:22:55 am »

I am trying to implement object clicking on my code that is basically a ripoff of the isotest app's code.

Here is the (relevant) code (and I apologize for the massive code paste but its just the isotest in reality with the code for clicking objects):

Code:
//GlobCrys.h

...

struct IsoView
{
  /// offset to apply to the camera.
  csVector3 camera_offset;
  /// original camera offset.
  csVector3 original_offset;
  /// angle of rotation, in degrees, 0.0 is the original rotation.
  float angle;
  /// distance from the lookat spot. 1.0 is original distance.
  float distance;

  /// initialize with csParticleoriginal offset of camera from the spot you look at.
  void SetOrigOffset(const csVector3& v)
  { camera_offset = original_offset = v; angle = 0.f; distance = 1.f; }
};

int current_view;
IsoView views[4];

...



//GlobCrys.cpp

GlobCrys::GlobCrys (iObjectRegistry* object_reg)
{
  GlobCrys::object_reg = object_reg;

  current_view = 0;
  views[0].SetOrigOffset (csVector3 (-4, 4, -4)); // true isometric perspective.
  views[1].SetOrigOffset (csVector3 (-9, 9, -9)); // zoomed out.
  views[2].SetOrigOffset (csVector3 (4, 3, -4)); // diablo style perspective.
  views[3].SetOrigOffset (csVector3 (0, 4, -4)); // zelda style perspective.

  actor_is_walking = false;
}

iMeshWrapper* GlobCrys::GetClickedObject (iCamera* camera, int mousex, int mousey)
{


  // Setup a 2D vector with our mouse position.  We invert the y
  // (based on vertical screen dimension) because CS assumes y=0
  // is down for 3D calculations.
  csVector2 v2d (mousex, camera->GetShiftY () * 2 - mousey);

  // We calculate the inverse perspective of this 2D point at
  // z=100.  This results in a 3D position in camera space at
  // z=100 that directly corresponds to the 2D position we
  // clicked on.  We use z=100 to ensure that we will at least
  // hit all objects that are before that distance.
  csVector3 v3d = camera->InvPerspective (v2d, 100);

  // We are going to cast a beam in the current sector of the
  // camera from our camera position in the direction of the
  // 'v3d' point.  First we transform the v3d camera space
  // location to world space.
  csVector3 startbeam = camera->GetTransform ().GetOrigin ();

  csVector3 endbeam = camera->GetTransform ().This2Other (v3d);


  iSector* beamsector = camera->GetSector ();
  // Now do the actual intersection.
  csSectorHitBeamResult result =
   beamsector->HitBeamPortals(startbeam, endbeam);
  //From the result object, return the intersected mesh.
  iMeshWrapper* mesh = result.mesh;
  return mesh;

}

void GlobCrys::SetupFrame ()
{
  // 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.03 * 90);

  if (kbd->GetModifierState (CSKEY_SHIFT_LEFT)
    || kbd->GetModifierState (CSKEY_SHIFT_RIGHT))
  {
    if (kbd->GetKeyState (CSKEY_RIGHT))
      views[current_view].angle += speed*15.f;
    if (kbd->GetKeyState (CSKEY_LEFT))
      views[current_view].angle -= speed*15.f;
    if (kbd->GetKeyState (CSKEY_UP))
      views[current_view].distance -= 0.25f*speed;
    if (kbd->GetKeyState (CSKEY_DOWN))
      views[current_view].distance += 0.25f*speed;
    SetupIsoView(views[current_view]);
  }
  ...
 
  csVector3 actor_pos = actor->GetMovable ()->GetPosition ();
  ...
 
  CameraIsoLookat(view->GetCamera(), views[current_view], actor_pos);
 
  ...
  // 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 GlobCrys::CameraIsoLookat(csRef<iCamera> cam, const IsoView& isoview,
    const csVector3& lookat)
{
  // Let the camera look at the actor.
  // so the camera is set to look at 'actor_pos'
  //int isofactor = 50; // 98.3% isometric (=GetFovAngle()/180.0)
  //int isofactor = 100; // 99.2% isometric (=GetFovAngle()/180.0)
  int isofactor = 200; // 99.6% isometric (=GetFovAngle()/180.0)

  // set center and lookat
  csOrthoTransform& cam_trans = cam->GetTransform ();
  cam_trans.SetOrigin (lookat + float(isofactor)*isoview.camera_offset);
  cam_trans.LookAt (lookat-cam_trans.GetOrigin (), csVector3 (0, 1, 0));
  // set fov more isometric, could be done in initialisation once.
  cam->SetFOV (g3d->GetHeight()*isofactor, g3d->GetWidth());

  // due to moving the camera so far away, depth buffer accuracy is
  // impaired, repair that by using smaller coordinate system
  csOrthoTransform repair_trans = cam->GetTransform();
  repair_trans.SetT2O (repair_trans.GetT2O()/repair_trans.GetOrigin().Norm());
  cam->SetTransform (repair_trans);
}

void GlobCrys::SetupIsoView(IsoView& isoview)
{
  // clamp
  if(isoview.angle < 0.f) isoview.angle += 360.f;
  if(isoview.angle > 360.f) isoview.angle -= 360.f;
  if(isoview.distance < 0.05f) isoview.distance = 0.05f;
  if(views[current_view].distance > 10.f) isoview.distance = 10.f;
  // setup
  csYRotMatrix3 r(isoview.angle * PI / 180.0);
  isoview.camera_offset = (r*isoview.original_offset)*isoview.distance;
}
...

bool GlobCrys::HandleEvent (iEvent& ev)
{

 ...

  else if (CS_IS_MOUSE_EVENT(name_reg, ev))
  {
    switch(csMouseEventHelper::GetEventType(&ev))
    {
    case csMouseEventTypeDown:
      switch(csMouseEventHelper::GetButton(&ev))
      {
case csmbLeft:
{
int last_x, last_y;
  last_x = csMouseEventHelper::GetX(&ev);
last_y = csMouseEventHelper::GetY(&ev);

clicked_mesh = GetClickedObject(view->GetCamera(),last_x,last_y);
if(!clicked_mesh)
{
   printf("Nothing there\n\n");
}
else
{
  printf("Something's there\n");
  printf("%s\n\n",clicked_mesh->QueryObject()->GetName());
      }
}
   
  ...
  return false;
}

Now I don't seem to able to figure out whats wrong but the object selection doesnt work at all. Now based on what was in this 'http://www.crystalspace3d.org/forum/index.php/topic,1104.0.html post I tried changing
Code:
csVector3 endbeam = camera->GetTransform ().This2Other (v3d);
to
Code:
csVector3 endbeam = camera->GetTransform ().This2OtherRelative (v3d);

This seems to give some hits, registers some meshes but is still way off the mark and inaccurate. I don't seem to be able to pick any of the objects that I need.

Please help.
« Last Edit: January 26, 2009, 07:16:08 pm by Hannofcart » Logged
Hannofcart
Newbie
*
Posts: 14


View Profile Email
« Reply #1 on: January 25, 2009, 10:41:12 pm »

Ok, so far the only headway I seem to have made with this is that
Code:
csVector3 endbeam = camera->GetTransform ().This2OtherRelative (v3d);
has to be used instead of
Code:
csVector3 endbeam = camera->GetTransform ().This2Other(v3d);
owing to the fact that the camera's origin is reset here everytime instead of using the more customary Move().

Though with this tinkering it registers the biggest mesh (so atleast something works) which is the floor/base of the map I have loaded, the click selection still doesn't register any of the other objects on it.

The current state of my click object function is
Code:
iMeshWrapper* GlobCrys::GetClickedObject (iCamera* camera, int mousex, int mousey)
{

printf("X Coord:");
printf("%d",mousex);
printf(" Y Coord:");
printf("%d",mousey);
printf("\n");
  // Setup a 2D vector with our mouse position.  We invert the y
  // (based on vertical screen dimension) because CS assumes y=0
  // is down for 3D calculations.
  csVector2 v2d (mousex, (float)(view->GetContext()->GetHeight()*2 - mousey));

  // We calculate the inverse perspective of this 2D point at
  // z=100.  This results in a 3D position in camera space at
  // z=100 that directly corresponds to the 2D position we
  // clicked on.  We use z=100 to ensure that we will at least
  // hit all objects that are before that distance.
  csVector3 v3d = camera->InvPerspective (v2d,200);
printf("Inv persp for the points are ");
printf(v3d.Description());
printf("\n");
  // We are going to cast a beam in the current sector of the
  // camera from our camera position in the direction of the
  // 'v3d' point.  First we transform the v3d camera space
  // location to world space.
  csVector3 startbeam = camera->GetTransform ().GetOrigin ();
printf("Camera origin ");
printf(startbeam.Description());
printf("\n");
  csVector3 endbeam = camera->GetTransform ().This2OtherRelative(v3d);

printf("Endpoint of Beam ");
printf(endbeam.Description());
printf("\n");



  iSector* beamsector = camera->GetSector ();
  // Now do the actual intersection.
  csSectorHitBeamResult result =
   beamsector->HitBeamPortals(startbeam, endbeam);
  //From the result object, return the intersected mesh.
  iMeshWrapper* mesh = result.mesh;
  printf("the point hit in world space was %f,%f,%f\n",result.isect.x,result.isect.y,result.isect.z);
  return mesh;

}

Ideas anyone? Please? Anyone? Just general directions as to what could possibly be the problem would do because as of now I am positively clueless.
« Last Edit: January 26, 2009, 06:38:47 pm by Hannofcart » Logged
Hannofcart
Newbie
*
Posts: 14


View Profile Email
« Reply #2 on: January 26, 2009, 07:13:57 pm »

After hours of vexation and some more debugging effort, thanks to the pointers that Jorrit gave on the IRC, I cheated and used a quick fix in the Bugplug code (again thanks to Jorrit for pointing me to that). All the code in the aforementioned GetClickedObject() function as found in the manual were replaced by these 4 beautifully simple lines of code I stole from bugplug.cpp:

Code:
iMeshWrapper* GlobCrys::GetClickedObject (iCamera* camera, int mousex, int mousey)
{
csScreenTargetResult result = csEngineTools::FindScreenTarget (
      csVector2 (mousex, mousey), 100.0f, camera);
  iMeshWrapper* sel = result.mesh;
return sel;
}

While this is probably not the right way (I ought to have taken the efforts to find out what was actually going wrong in MY code before I used the csEngineTools routines), it was much simpler than the code in the manual which though it teaches you HOW its really done (in fact I believe the csEngineTools methods do the same thing, correctly I suppose), is still more code to wrap your mind around.

So, I suggest we just use this code in the manual, or aleast leave some signs pointing to the csEngineTools class (atleast for the benefit of the lazy dullards like me who could always use more abstraction Smiley ).
Logged
Pages: [1] Print 
« previous next »
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC Valid XHTML 1.0! Valid CSS!
Page created in 6.537 seconds with 16 queries.