/**
 * SceneGraph が増えてくると動かなくなるかもしれない。
 * 一応 mainMem とかで動くようになるとは思うけど。
 * だめだったら、そこら辺が怪しいと思うべき
 */

#include "CreatePolygonFromSceneGraph.h"
#include "polygon_pack.h"
#include "texture.h"

SchedDefineTask(CreatePolygonFromSceneGraph);

/**
 *  ベクトルに行列を乗算する
 * @param[out] v vector (float[4])
 * @param[in] m matrix (float[16])
 */
static void
ApplyMatrix(float *v, float *m)
{
    float t[4];

    t[0] = v[0];
    t[1] = v[1];
    t[2] = v[2];
    t[3] = v[3];

    for (int i = 0; i < 4; i++) {
	v[i] = t[0]*m[i] + t[1]*m[i+4] + t[2]*m[i+8] + t[3]*m[i+12];
    }
}


static int 
run(SchedTask *smanager, void *rbuf, void *wbuf)
{
    float xyz1[4], xyz2[4], xyz3[4];
    float normal1[4],normal2[4],normal3[4];

    //pp, matrix, real_matrix を受け取る
    PolygonPackPtr in_pp      = (PolygonPackPtr)smanager->get_input(rbuf, 0);
    float *matrix             = (float*)smanager->get_input(rbuf, 1);
    float *real_matrix        = (float*)smanager->get_input(rbuf, 2);
    texture_list *tritexinfo  = (texture_list*)smanager->get_input(rbuf, 3);
    
    PolygonPackPtr next = (PolygonPackPtr)smanager->get_param(0);


    PolygonPackPtr out_pp = (PolygonPackPtr)smanager->get_output(wbuf, 0);
    out_pp->info.size = in_pp->info.size;
    out_pp->next = next;

    if (in_pp->info.size == 0) {
      printf("in_pp->info.size = 0\n");
    }

    for (int i = 0; i < in_pp->info.size; i++) {

      TrianglePack tri = in_pp->tri[i];
      
      xyz1[0] = tri.ver1.x;
      xyz1[1] = tri.ver1.y;
      xyz1[2] = tri.ver1.z * -1.0f;
      xyz1[3] = 1.0f;
      
      xyz2[0] = tri.ver2.x;
      xyz2[1] = tri.ver2.y;
      xyz2[2] = tri.ver2.z * -1.0f;
      xyz2[3] = 1.0f;
      
      xyz3[0] = tri.ver3.x;
      xyz3[1] = tri.ver3.y;
      xyz3[2] = tri.ver3.z * -1.0f;
      xyz3[3] = 1.0f;
      
      // matrix = 回転行列*透視変換行列
      ApplyMatrix(xyz1, matrix);
      ApplyMatrix(xyz2, matrix);
      ApplyMatrix(xyz3, matrix);
      
      xyz1[0] /= xyz1[2];
      xyz1[1] /= xyz1[2];
      xyz2[0] /= xyz2[2];
      xyz2[1] /= xyz2[2];
      xyz3[0] /= xyz3[2];
      xyz3[1] /= xyz3[2];
   
      TrianglePackPtr triangle = &out_pp->tri[i];

      triangle->ver1.x = xyz1[0];
      triangle->ver1.y = xyz1[1];
      triangle->ver1.z = xyz1[2];
      triangle->ver1.tex_x = tri.ver1.tex_x;
      triangle->ver1.tex_y = tri.ver1.tex_y;
      
      triangle->ver2.x = xyz2[0];
      triangle->ver2.y = xyz2[1];
      triangle->ver2.z = xyz2[2];
      triangle->ver2.tex_x = tri.ver2.tex_x;
      triangle->ver2.tex_y = tri.ver2.tex_y;
      
      triangle->ver3.x = xyz3[0];
      triangle->ver3.y = xyz3[1];
      triangle->ver3.z = xyz3[2];
      triangle->ver3.tex_x = tri.ver3.tex_x;
      triangle->ver3.tex_y = tri.ver3.tex_y;
      
      normal1[0] = tri.normal1.x;
      normal1[1] = tri.normal1.y;
      normal1[2] = tri.normal1.z * -1.0f;
      //normal1[3] = 1.0f;
      normal1[3] = 0.0f;
      
      normal2[0] = tri.normal2.x;
      normal2[1] = tri.normal2.y;
      normal2[2] = tri.normal2.z * -1.0f;
      //normal2[3] = 1.0f;
      normal2[3] = 0.0f;
      
      normal3[0] = tri.normal3.x;
      normal3[1] = tri.normal3.y;
      normal3[2] = tri.normal3.z * -1.0f;
      //normal3[3] = 1.0f;
      normal3[3] = 0.0f;
      
      ApplyMatrix(normal1,real_matrix);
      ApplyMatrix(normal2,real_matrix);
      ApplyMatrix(normal3,real_matrix);
      
      normal1[0] /= normal1[2];
      normal1[1] /= normal1[2];
      
      normal2[0] /= normal2[2];
      normal2[1] /= normal2[2];
      
      normal3[0] /= normal3[2];
      normal3[1] /= normal3[2];
      
      triangle->normal1.x = normal1[0];
      triangle->normal1.y = normal1[1];
      triangle->normal1.z = normal1[2];
      
      triangle->normal2.x = normal2[0];
      triangle->normal2.y = normal2[1];
      triangle->normal2.z = normal2[2];
      
      triangle->normal3.x = normal3[0];
      triangle->normal3.y = normal3[1];
      triangle->normal3.z = normal3[2];
      
      triangle->tex_info.addr   = tritexinfo->pixels;
      triangle->tex_info.width  = tritexinfo->t_w;
      triangle->tex_info.height = tritexinfo->t_h;
      triangle->tex_info.scale_max = tritexinfo->scale_max;
    }

    return 0;
}
