/****************************************************************************
* MeshLab                                                           o o     *
* A versatile mesh processing toolbox                             o     o   *
*                                                                _   O  _   *
* Copyright(C) 2005                                                \/)\/    *
* Visual Computing Lab                                            /\/|      *
* ISTI - Italian National Research Council                           |      *
*                                                                    \      *
* All rights reserved.                                                      *
*                                                                           *
* 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; either version 2 of the License, or         *
* (at your option) any later version.                                       *
*                                                                           *
* 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 (http://www.gnu.org/licenses/gpl.txt)          *
* for more details.                                                         *
*                                                                           *
****************************************************************************/

#ifndef _RASTERING_H
#define _RASTERING_H

#include <QtGui>
#include <vcg/complex/algorithms/point_sampling.h>
#include <vcg/space/triangle2.h>
#include <common/ml_document/mesh_model.h>


// texel descriptor---------------------------------

typedef struct{

  vcg::Point2i texcoord;

  Point3m meshpoint;
  Point3m meshnormal;

} TexelDesc;

typedef struct{

  float weights;
  float acc_red;
  float acc_grn;
  float acc_blu;

} TexelAccum;


//--------------------------------------------------

//----------- TEXTURE FILLING SAMPLER ------------------------------
/*
class TexFillSampler
{
    public:
    TexFillSampler(CMeshO* _m){m=_m; uvSpaceFlag = false; qualitySampling=false; tex=0;};
    CMeshO *m;
    QImage* tex;
    int texSamplingWidth;
    int texSamplingHeight;
    bool uvSpaceFlag;
    bool qualitySampling;
    texwork *thiswork;

    void AddVert(const MyMesh::VertexType &p)
    {
    }

    void AddFace(const MyMesh::FaceType &f, MyMesh::CoordType p)
    {
    }

    void AddTextureSample(const MyMesh::FaceType &f, const MyMesh::CoordType &p, const Point2i &tp, float edgeDist=0)
    {
        double rr,gg,bb;
        double count;
        QColor col;
        float  weight;
        Point2f ppoint;
        Point3f pray;
        float dpt,ref;

        Point3f meshpoint = f.P(0)*p[0] + f.P(1)*p[1] +f.P(2)*p[2];
        Point3f meshnorm  = f.V(0)->N()*p[0] + f.V(1)->N()*p[1] +f.V(2)->N()*p[2];

        rr = gg = bb = 0;
        count = 0;
        for(int camit=0; camit<thiswork->camnum; camit++)
        {
            ppoint = thiswork->immagini[camit].imshot->Project(meshpoint);
            // pray is the vector from the point-to-be-colored to the camera center
            pray = (thiswork->immagini[camit].imshot->Extrinsics.Tra() - meshpoint).Normalize();


            if((ppoint[0] > 0) && (ppoint[0] < thiswork->immagini[camit].imshot->Intrinsics.ViewportPx.X()) &&
              (ppoint[1] > 0) && (ppoint[1] < thiswork->immagini[camit].imshot->Intrinsics.ViewportPx.Y()))
                if((meshnorm.dot(-thiswork->immagini[camit].imshot->Axis(2))) <= 0.0)
                if((pray.dot(-thiswork->immagini[camit].imshot->Axis(2))) <= 0.0)
                {

                    dpt  = (thiswork->immagini[camit].imshot->Depth(meshpoint) - thiswork->depth_eta);
                    ref  = thiswork->immagini[camit].camdepth.getval(ppoint[0],ppoint[1]);

                    if(dpt < ref)
                    {
                        weight = thiswork->immagini[camit].camweight.getval(ppoint[0],ppoint[1]);
                        ppoint[1] = thiswork->immagini[camit].imshot->Intrinsics.ViewportPx.Y() - ppoint[1];
                        col = thiswork->immagini[camit].impicture->pixel(ppoint[0],ppoint[1]);

                        if((col.red() + col.green() + col.blue()) > 0)
                        {
                         rr += col.red()*weight; gg += col.green()*weight; bb += col.blue()*weight;
                         count += weight;
                        }
                    }
                }
        }

        if(count > 0)
        {
            rr = (double)rr/count;
            gg = (double)gg/count;
            bb = (double)bb/count;

            // updating color mean
            if(thiswork->usemean)
            {
                thiswork->meanrr = (thiswork->meanrr * 10.0 + rr) / 11.0;
                thiswork->meangg = (thiswork->meangg * 10.0 + gg) / 11.0;
                thiswork->meanbb = (thiswork->meanbb * 10.0 + bb) / 11.0;
            }
        }
        else	// default color
        {
            rr = thiswork->meanrr;
            gg = thiswork->meangg;
            bb = thiswork->meanbb;
        }

//--------------------------

        tex->setPixel(tp[0], texSamplingHeight - tp[1], qRgb(rr,gg,bb));



    }
}; // end class TexFillSampler
//------------------------------------------------------------------

*/


class TexFillerSampler
{
public:

    QImage &trgImg;

    vector<TexelDesc> *texelspointer; // list of active texels to be filled
    vector<TexelAccum> *accumpointer;  // list of color + weight accumulators

    // Callback stuff
    vcg::CallBackPos *cb;
    const CMeshO::FaceType *currFace;
    int faceNo, faceCnt, start, offset;


    TexFillerSampler(QImage &_img) : trgImg(_img) {}

    void InitCallback(vcg::CallBackPos *_cb, int _faceNo, int _start=0, int _offset=100)
    {
        assert(_faceNo > 0);
        assert(_start>=0);
        assert(_offset>=0 && _offset <= 100-_start);
        cb = _cb;
        faceNo = _faceNo;
        faceCnt = 0;
        start = _start;
        offset = _offset;
        currFace = NULL;
    }

    // expects points outside face (affecting face color) with edge distance > 0
    void AddTextureSample(const CMeshO::FaceType &f, const CMeshO::CoordType &p, const vcg::Point2i &tp, float /*edgeDist*/)
    {
        Point3m meshpoint = f.cP(0)*p[0] + f.cP(1)*p[1] +f.cP(2)*p[2];
        Point3m meshnorm  = (f.cV(0)->N()*p[0] + f.cV(1)->N()*p[1] + f.cV(2)->N()*p[2]).Normalize();

      TexelDesc newtexel;
      newtexel.texcoord = tp;
      newtexel.meshpoint.Import(meshpoint);
      newtexel.meshnormal.Import(meshnorm);

      TexelAccum newaccum;
      newaccum.weights = 0.0;
      newaccum.acc_red = 0.0;
      newaccum.acc_grn = 0.0;
      newaccum.acc_blu = 0.0;

      texelspointer->push_back(newtexel);
      accumpointer->push_back(newaccum);
    }
}; // end class TexFillerSampler



#endif
