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):
//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
csVector3 endbeam = camera->GetTransform ().This2Other (v3d);
to
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.