/* * 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) { }