//------------------------------------------------------------------;
//
//------------------------------------------------------------------;

c_obj::c_obj () {

}

//------------------------------------------------------------------;
//
//------------------------------------------------------------------;

c_obj::~c_obj () {

   delete [] e_obj;

}

//------------------------------------------------------------------;
//
//------------------------------------------------------------------;

void c_obj::m_load_model( void ) {

   mat3           basis;
   vec3           face_normal;
   int            j, j_times_3;
   unsigned int   size;
   unsigned char *buf;

   // Load the .ASE files from ZIP volume
   buf = unzip::open("obj/l_leaf_models.zip", "leaf.ase", &size);

   if (buf == NULL) {
      cerr << "Failed to find the ASE model" << endl;
      exit(0);
   }

   e_nv->model = ase::load((char *)buf,size, 0.1);

   delete [] buf;
   // Load the textures
   ase::load_tex          (e_nv->model);
   e_img->m_load_tex      (e_nv->model);
   e_img->m_load_bump_tex (e_nv->model);

   // Process the ase::model
   ase::geom_it it = e_nv->model->geom.begin();
   while (it != e_nv->model->geom.end()) {

      ase::geomobj * geom = *it;
      // we need vertices and texture coordinates
      // in order to construct the tangent basis
      // required for bump mapping.
      if (geom->numv && geom->numt) {

         nv_mesh * mesh = new nv_mesh;
            
         mesh->name     = geom->name;
         mesh->numv     = geom->numv;
         mesh->v        = new float[mesh->numv * 3];
         mesh->tangent  = new float[mesh->numv * 3];
         mesh->binormal = new float[mesh->numv * 3];
         mesh->normal   = new float[mesh->numv * 3];

         memset (mesh->tangent,0, mesh->numv * sizeof(float) * 3);
         memset (mesh->binormal,0, mesh->numv * sizeof(float) * 3);
         memset (mesh->normal,0, mesh->numv * sizeof(float) * 3);
         memcpy (mesh->v, geom->v, mesh->numv * sizeof(float) * 3);

         mesh->t    = new float[mesh->numv * 2];
         mesh->numf = geom->numf;
         mesh->f    = new int[mesh->numf * 3];
         memcpy (mesh->f, geom->f, mesh->numf * sizeof(int) * 3);

         mesh->matidx = geom->matidx;

         for (j = 0; j < mesh->numf; ++j) {

            j_times_3 = j * 3;

            int v0_idx = geom->f[j_times_3];
            int v1_idx = geom->f[j_times_3 + 1];
            int v2_idx = geom->f[j_times_3 + 2];
            int n0_idx = geom->fvn[j_times_3];
            int n1_idx = geom->fvn[j_times_3 + 1];
            int n2_idx = geom->fvn[j_times_3 + 2];
            int t0_idx = geom->tf[j_times_3];
            int t1_idx = geom->tf[j_times_3 + 1];
            int t2_idx = geom->tf[j_times_3 + 2];

            float  * n0 = &geom->n[n0_idx * 3];
            float  * n1 = &geom->n[n1_idx * 3];
            float  * n2 = &geom->n[n2_idx * 3];

            // Compute the face normal based on vertex normals
            face_normal.x = n0[0] + n1[0] + n2[0];
            face_normal.y = n0[1] + n1[1] + n2[1];
            face_normal.z = n0[2] + n1[2] + n2[2];

            normalize(face_normal);

            mesh->t[v0_idx * 2] = geom->t[t0_idx * 3];
            mesh->t[v0_idx * 2 + 1] = geom->t[t0_idx * 3 + 1];
            mesh->t[v1_idx * 2] = geom->t[t1_idx * 3];
            mesh->t[v1_idx * 2 + 1] = geom->t[t1_idx * 3 + 1];
            mesh->t[v2_idx * 2] = geom->t[t2_idx * 3];
            mesh->t[v2_idx * 2 + 1] = geom->t[t2_idx * 3 + 1];

            int v0_times_3 = v0_idx * 3;
            int v1_times_3 = v1_idx * 3;
            int v2_times_3 = v2_idx * 3;
            vec3 v0(&geom->v[v0_times_3]);
            vec3 v1(&geom->v[v1_times_3]);
            vec3 v2(&geom->v[v2_times_3]);
            vec2 t0(&mesh->t[v0_idx * 2]);
            vec2 t1(&mesh->t[v1_idx * 2]);
            vec2 t2(&mesh->t[v2_idx * 2]);
               
            tangent_basis( basis, v0, v1, v2, t0, t1, t2, face_normal);

            mesh->tangent[v0_times_3] += basis.a00;
            mesh->tangent[v0_times_3 + 1] += basis.a01;
            mesh->tangent[v0_times_3 + 2] += basis.a02;
                
            mesh->binormal[v0_times_3] += basis.a10;
            mesh->binormal[v0_times_3 + 1] += basis.a11;
            mesh->binormal[v0_times_3 + 2] += basis.a12;

            mesh->normal[v0_times_3] += basis.a20;
            mesh->normal[v0_times_3 + 1] += basis.a21;
            mesh->normal[v0_times_3 + 2] += basis.a22;

            mesh->tangent[v1_times_3] += basis.a00;
            mesh->tangent[v1_times_3 + 1] += basis.a01;
            mesh->tangent[v1_times_3 + 2] += basis.a02;
            
            mesh->binormal[v1_times_3] += basis.a10;
            mesh->binormal[v1_times_3 + 1] += basis.a11;
            mesh->binormal[v1_times_3 + 2] += basis.a12;

            mesh->normal[v1_times_3] += basis.a20;
            mesh->normal[v1_times_3 + 1] += basis.a21;
            mesh->normal[v1_times_3 + 2] += basis.a22;

            mesh->tangent[v2_times_3] += basis.a00;
            mesh->tangent[v2_times_3 + 1] += basis.a01;
            mesh->tangent[v2_times_3 + 2] += basis.a02;
            
            mesh->binormal[v2_times_3] += basis.a10;
            mesh->binormal[v2_times_3 + 1] += basis.a11;
            mesh->binormal[v2_times_3 + 2] += basis.a12;

            mesh->normal[v2_times_3] += basis.a20;
            mesh->normal[v2_times_3 + 1] += basis.a21;
            mesh->normal[v2_times_3 + 2] += basis.a22;
         }
         for (j = 0; j < mesh->numv; ++j) {

            j_times_3 = j * 3;
            vec3 tangent(&mesh->tangent[j_times_3]);
            normalize(tangent);
            mesh->tangent[j_times_3] = tangent.x;
            mesh->tangent[j_times_3 + 1] = tangent.y;
            mesh->tangent[j_times_3 + 2] = tangent.z;

            vec3 binormal(&mesh->binormal[j_times_3]);
            normalize(binormal);
            mesh->binormal[j_times_3] = binormal.x;
            mesh->binormal[j_times_3 + 1] = binormal.y;
            mesh->binormal[j_times_3 + 2] = binormal.z;

            vec3 normal(&mesh->normal[j_times_3]);
            normalize(normal);
            mesh->normal[j_times_3] = normal.x;
            mesh->normal[j_times_3 + 1] = normal.y;
            mesh->normal[j_times_3 + 2] = normal.z;
         }
         e_nv->mesh_array.push_back(mesh);
      }
      ++it;
   }
}

//------------------------------------------------------------------;
// load(x)->convert to custom FVF.
//------------------------------------------------------------------;

void c_obj::m_load_x_file ( const char* l_file, 
                            const DWORD l_fvf ) {

   ID3DXMesh *l_mesh_raw = NULL; // raw/mesh
   ID3DXMesh *l_mesh_opt = NULL; // opt/mesh
   ID3DXMesh *l_mesh_fvf = NULL; // mesh/conv FVF
		
   D3DXLoadMeshFromX ( const_cast<char*>(l_file),
                       D3DXMESH_SYSTEMMEM, 
                       e_d3d->l_d3d_device, 
                       NULL,
                       NULL,
                       NULL, 
                       &e_d3d->l_num_sections, 
                       &l_mesh_raw );

   l_mesh_raw->Optimize          ( D3DXMESHOPT_ATTRSORT, NULL, NULL, NULL, NULL, &l_mesh_opt );
   l_mesh_opt->GetAttributeTable ( NULL, &e_d3d->l_num_sections );

   m_safe_delete_array           ( e_d3d->l_attributes );

   e_d3d->l_attributes = new D3DXATTRIBUTERANGE[e_d3d->l_num_sections];
	
   l_mesh_opt->GetAttributeTable ( e_d3d->l_attributes, &e_d3d->l_num_sections );

   m_safe_release                ( e_d3d->l_vertex_buffer );
   m_safe_release                ( e_d3d->l_index_buffer );

   // custom format
   l_mesh_opt->CloneMeshFVF( D3DXMESH_WRITEONLY, l_fvf, e_d3d->l_d3d_device, &l_mesh_fvf );
	
   l_mesh_fvf->GetVertexBuffer   ( &e_d3d->l_vertex_buffer );
   l_mesh_fvf->GetIndexBuffer    ( &e_d3d->l_index_buffer );

   m_safe_release ( l_mesh_raw );
   m_safe_release ( l_mesh_opt );
   m_safe_release ( l_mesh_fvf );

}
