/*
* 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 "ivideo/txtmgr.h"
#include "ivideo/material.h"
#include "ivaria/reporter.h"
#include "ivaria/stdrep.h"
#include "iutil/document.h"
#include "pv_helpers.h"
// Static member initialization
iObjectRegistry *DirectionArrow::object_reg=NULL;
iEngine *DirectionArrow::engine=NULL;
iMaterialWrapper *DirectionArrow::arrow_material_wrapper=NULL;
iShader *DirectionArrow::arrow_shader=NULL;
const char *DirectionArrow::shader_string =
""
""
""
""
""
"";
DirectionArrow::DirectionArrow(iObjectRegistry* o_reg,iSector *sector, csVector3 position,csVector3 direction,float length)
: loc_position(position), loc_direction(direction)
{
loc_sector=sector;
loc_length=length;
if (object_reg == NULL)
object_reg=o_reg;
if (!engine)
{
csRef temp_engine;
temp_engine = CS_QUERY_REGISTRY (object_reg, iEngine);
engine=temp_engine;
engine->IncRef();
}
arrow_factory_wrapper=NULL;
arrow_mesh=NULL;
shown=false;
}
DirectionArrow::~DirectionArrow()
{
if (engine)
{
engine->RemoveObject(arrow_mesh_wrapper);
engine->RemoveObject(arrow_factory_wrapper);
}
}
bool DirectionArrow::Initialize()
{
iMovable *arrow_movable;
if (!object_reg || !engine)
return false;
if (!InitializeArrowFactory())
return false;
if (arrow_mesh)
return true;
arrow_mesh=arrow_factory_wrapper->GetMeshObjectFactory()->NewInstance();
arrow_mesh_wrapper=engine->CreateMeshWrapper(arrow_mesh,NULL,loc_sector,loc_position);
arrow_movable=arrow_mesh_wrapper->GetMovable();
csVector3 other_vector;
if (loc_direction.x > -0.00001f && loc_direction.x < 0.00001f)
other_vector.Set(1.0f,0.0f,0.0f);
else
other_vector.Set(0.0f,1.0f,0.0f);
csVector3 x_axis,z_axis;
x_axis=loc_direction % other_vector;
z_axis=loc_direction % x_axis;
loc_direction.Normalize();
x_axis.Normalize();
z_axis.Normalize();
/*
csMatrix3 rot_matrix(
x_axis.x,x_axis.y,x_axis.z,
loc_direction.x,loc_direction.y,loc_direction.z,
z_axis.x,z_axis.y,z_axis.z);
*/
csMatrix3 rot_matrix(
x_axis.x,loc_direction.x,z_axis.x,
x_axis.y,loc_direction.y,z_axis.y,
x_axis.z,loc_direction.z,z_axis.z
);
arrow_movable->Transform(rot_matrix);
arrow_movable->UpdateMove();
engine->PrepareMeshes();
shown=true;
return true;
}
void DirectionArrow::MoveTo(csVector3 position)
{
iMovable *arrow_movable;
if (!object_reg || !engine)
return;
if (!arrow_mesh)
return;
arrow_movable=arrow_mesh_wrapper->GetMovable();
if (!arrow_movable)
return;
loc_position=position;
arrow_movable->SetPosition(position);
arrow_movable->UpdateMove();
}
void DirectionArrow::PointTo(csVector3 direction)
{
iMovable *arrow_movable;
if (!object_reg || !engine)
return;
if (!arrow_mesh)
return;
arrow_movable=arrow_mesh_wrapper->GetMovable();
if (!arrow_movable)
return;
loc_direction=direction;
csVector3 other_vector;
if (loc_direction.x > -0.00001f && loc_direction.x < 0.00001f)
other_vector.Set(1.0f,0.0f,0.0f);
else
other_vector.Set(0.0f,1.0f,0.0f);
csVector3 x_axis,z_axis;
x_axis=loc_direction % other_vector;
z_axis=loc_direction % x_axis;
loc_direction.Normalize();
x_axis.Normalize();
z_axis.Normalize();
csMatrix3 rot_matrix(
x_axis.x,loc_direction.x,z_axis.x,
x_axis.y,loc_direction.y,z_axis.y,
x_axis.z,loc_direction.z,z_axis.z
);
arrow_movable->SetTransform(rot_matrix);
arrow_movable->UpdateMove();
}
void DirectionArrow::Hide()
{
if (!shown)
return;
arrow_mesh_wrapper->GetMovable()->ClearSectors();
arrow_mesh_wrapper->PlaceMesh();
shown=false;
}
void DirectionArrow::Show()
{
if (shown)
return;
arrow_mesh_wrapper->GetMovable()->SetSector(loc_sector);
arrow_mesh_wrapper->PlaceMesh();
shown=true;
}
/*
D
9A 56 78 BC
12 34
verts =
0 -0.1, 0 , 0.1
1 -0.1, 0 , -0.1
2 0.1, 0 , -0.1
3 0.1, 0 , 0.1
4 -0.1, 0.8 , 0.1
5 -0.1, 0.8 , -0.1
6 0.1, 0.8 , -0.1
7 0.1, 0.8 , 0.1
8 -0.2, 0.8, 0.2
9 -0.2, 0.8, -0.2
10 0.2, 0.8, -0.2
11 0.2, 0.8, 0.2
12 0.0, 1.0, 0.0
(top view)
1 2
0 3
(top view)
5 6
4 7
(top view)
9 10
12
8 11
tri indices =
// bottom
0 3,1,0
1 2,1,3
// front
2 0,4,3
3 4,7,3
// left
4 1,5,0
5 0,5,4
// rear
6 2,6,1
7 1,6,5
// right
8 3,7,2
9 2,7,6
// bottom of arrowhead
10 9,8,11
11 10,9,11
// front face
12 8,12,11
// left face
13 9,12,8
// rear face
14 10,12,9
// right face
15 11,12,10
*/
bool DirectionArrow::InitializeArrowFactory()
{
int i;
csVector3 *vert_array;
csTriangle *tri_array;
csColor *color_array;
// Only needs to be setup once
if (arrow_factory_wrapper)
return true;
if (!InitializeArrowMaterial())
return false;
csRef temp_factory = engine->CreateMeshFactory("crystalspace.mesh.object.genmesh","DirectionArrowFactory");
arrow_factory_wrapper=temp_factory;
if (!arrow_factory_wrapper)
return false;
arrow_factory_wrapper->IncRef();
iMeshObjectFactory *arrow_factory=arrow_factory_wrapper->GetMeshObjectFactory();
csRef factory_state = SCF_QUERY_INTERFACE(arrow_factory,iGeneralFactoryState);
factory_state->SetManualColors(true);
factory_state->SetLighting(false);
factory_state->SetVertexCount(13);
factory_state->SetTriangleCount(16);
vert_array=factory_state->GetVertices();
vert_array[0].Set(-0.005f,0.0f,0.005f);
vert_array[1].Set(-0.005f,0.0f,-0.005f);
vert_array[2].Set(0.005f,0.0f,-0.005f);
vert_array[3].Set(0.005f,0.0f,0.005f);
// Vertices below this point should have their y value scaled by length
vert_array[4].Set(-0.005f,0.8f * loc_length,0.005f);
vert_array[5].Set(-0.005f,0.8f * loc_length,-0.005f);
vert_array[6].Set(0.005f,0.8f * loc_length,-0.005f);
vert_array[7].Set(0.005f,0.8f * loc_length,0.005f);
vert_array[8].Set(-0.02f,0.8f * loc_length,0.02f);
vert_array[9].Set(-0.02f,0.8f * loc_length,-0.02f);
vert_array[10].Set(0.02f,0.8f * loc_length,-0.02f);
vert_array[11].Set(0.02f,0.8f * loc_length,0.02f);
vert_array[12].Set(0.0f,1.0f * loc_length,0.0f);
tri_array=factory_state->GetTriangles();
tri_array[0].Set(3,1,0);
tri_array[1].Set(2,1,3);
tri_array[2].Set(0,4,3);
tri_array[3].Set(4,7,3);
tri_array[4].Set(1,5,0);
tri_array[5].Set(0,5,4);
tri_array[6].Set(2,6,1);
tri_array[7].Set(1,6,5);
tri_array[8].Set(3,7,2);
tri_array[9].Set(2,7,6);
tri_array[10].Set(9,8,11);
tri_array[11].Set(10,9,11);
tri_array[12].Set(8,12,11);
tri_array[13].Set(9,12,8);
tri_array[14].Set(10,12,9);
tri_array[15].Set(11,12,10);
color_array=factory_state->GetColors();
for (i=0;i<13;i++)
color_array[i].Set(0.1f,0.8f,0.1f);
factory_state->SetMaterialWrapper(arrow_material_wrapper);
factory_state->CalculateNormals();
factory_state->Invalidate();
return true;
}
bool DirectionArrow::InitializeArrowMaterial()
{
csColor transp(0,0,0);
if (arrow_material_wrapper)
return true;
if (!InitializeArrowShader())
return false;
// We need an interface to the stringset object to retrieve common global string IDs
csRef strings = CS_QUERY_REGISTRY_TAG_INTERFACE (object_reg, "crystalspace.shared.stringset", iStringSet);
if (!strings)
{
csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "DirectionArrow::InitializeArrowMaterial()","Could not find an iStringSet interface in the available plugins!");
return false;
}
iTextureWrapper *arrow_texture=engine->CreateBlackTexture("DirectionArrowPsuedoTexture",1,1,&transp,CS_TEXTURE_3D);
csRef arrow_material=engine->CreateBaseMaterial(arrow_texture);
arrow_material->SetShader(strings->Request("OR compatibility"),arrow_shader);
arrow_material_wrapper=engine->GetMaterialList()->NewMaterial(arrow_material, 0);
engine->PrepareTextures();
return (arrow_material_wrapper!=NULL);
}
bool DirectionArrow::InitializeArrowShader()
{
if (arrow_shader!=NULL)
return true;
// We need a document system to parse the shader definition
csRef docsys (CS_QUERY_REGISTRY(object_reg, iDocumentSystem));
if (!docsys)
{
csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "DirectionArrow::InitializeArrowShader()","Could not find an iDocumentSystem interface in the available plugins!");
return false;
}
csRef shaderDoc=docsys->CreateDocument();
shaderDoc->Parse(shader_string);
// 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));
if (!shmgr)
{
csReport(object_reg,CS_REPORTER_SEVERITY_ERROR, "DirectionArrow::InitializeArrowShader()","Could not find an iShaderManager interface in the available plugins!");
return false;
}
// 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 temp_arrow_shader = shcom->CompileShader (shaderDoc->GetRoot ()->GetNode ("shader"));
arrow_shader = temp_arrow_shader;
arrow_shader->IncRef();
return (arrow_shader!=NULL);
}
void DirectionArrow::SetShaftColor(csColor c)
{
int i;
csColor *color_array;
if (!arrow_factory_wrapper)
return;
iMeshObjectFactory *arrow_factory=arrow_factory_wrapper->GetMeshObjectFactory();
csRef factory_state = SCF_QUERY_INTERFACE(arrow_factory,iGeneralFactoryState);
color_array=factory_state->GetColors();
for (i=0;i<8;i++)
color_array[i]=c;
factory_state->Invalidate();
}
void DirectionArrow::SetHeadColor(csColor c)
{
int i;
csColor *color_array;
if (!arrow_factory_wrapper)
return;
iMeshObjectFactory *arrow_factory=arrow_factory_wrapper->GetMeshObjectFactory();
csRef factory_state = SCF_QUERY_INTERFACE(arrow_factory,iGeneralFactoryState);
color_array=factory_state->GetColors();
for (i=8;i<13;i++)
color_array[i]=c;
factory_state->Invalidate();
}
SCF_IMPLEMENT_IBASE (CoordinateArrows)
SCF_IMPLEMENTS_INTERFACE (iMovableListener)
SCF_IMPLEMENT_IBASE_END
CoordinateArrows::CoordinateArrows(iObjectRegistry* o_reg,iSector *sector, csVector3 position,csVector3 vec_y,csVector3 vec_x ,float arrow_offset, float arrow_length)
{
csVector3 vec_z = vec_x % vec_y;
vec_x.Normalize();
vec_y.Normalize();
vec_z.Normalize();
offset=arrow_offset;
length=arrow_length;
arrow_x=new DirectionArrow(o_reg,sector,position+vec_x * arrow_offset,vec_x,arrow_length);
arrow_y=new DirectionArrow(o_reg,sector,position+vec_y * arrow_offset,vec_y,arrow_length);
arrow_z=new DirectionArrow(o_reg,sector,position+vec_z * arrow_offset,vec_z,arrow_length);
}
CoordinateArrows::~CoordinateArrows()
{
delete arrow_x;
arrow_x=NULL;
delete arrow_y;
arrow_y=NULL;
delete arrow_z;
arrow_z=NULL;
}
bool CoordinateArrows::Initialize()
{
bool success=true;
if (!arrow_x || !arrow_y || !arrow_z)
return false;
success&=arrow_x->Initialize();
success&=arrow_y->Initialize();
success&=arrow_z->Initialize();
arrow_x->SetHeadColor(csColor(1.0,0,0));
arrow_y->SetHeadColor(csColor(0,0,1.0));
arrow_z->SetHeadColor(csColor(1.0,0,1.0));
return success;
}
void CoordinateArrows::Show()
{
if (arrow_x)
arrow_x->Show();
if (arrow_y)
arrow_y->Show();
if (arrow_z)
arrow_z->Show();
}
void CoordinateArrows::Hide()
{
if (arrow_x)
arrow_x->Hide();
if (arrow_y)
arrow_y->Hide();
if (arrow_z)
arrow_z->Hide();
}
void CoordinateArrows::MovableChanged(iMovable* movable)
{
csVector3 position,vec_x,vec_y,vec_z;
position=movable->GetFullPosition();
csReversibleTransform trans=movable->GetFullTransform();
csMatrix3 trans_mat=trans.GetO2T();
vec_x=trans_mat.Row1();
vec_y=trans_mat.Row2();
vec_z=trans_mat.Row3();
if (arrow_x)
{
arrow_x->MoveTo(position + (vec_x * offset));
arrow_x->PointTo(vec_x);
}
if (arrow_y)
{
arrow_y->MoveTo(position + (vec_y * offset));
arrow_y->PointTo(vec_y);
}
if (arrow_z)
{
arrow_z->MoveTo(position + (vec_z * offset));
arrow_z->PointTo(vec_z);
}
}
/// The movable is about to be destroyed.
void CoordinateArrows::MovableDestroyed(iMovable* movable)
{
}