﻿/*
	Detecção de movimento com Webcam
	Desenvolvido por Murillo Brandão
	Sob orientação do Prof. Dr. Luciano Vieira de Araújo
 */

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;

public class Webcam : MonoBehaviour {

	/*
		PARAMETROS
		Display - RawImage para exibir o blend
		threshold - sensibilidade da detecção
		blendColor - cor de exibição da detecção
	 */
	public RawImage Display;

	[Range(0, 255)]
	public int threshold = 30;
	[Range(0f, 1f)]
	public float density = .02f;

	public Color32 blendColor = new Color32(255,255,255,255);


	bool initialized = false;
	WebCamTexture webcamTexture;
	Texture2D blendTexture;
	int diffsum = 0;
	int nullCount = 0;

	Color32[] lastData = null;
	Color32[] blendData = null;
	Color32[] checkData = null;

	[HideInInspector]
	public float scale = 1f;
	// Escala da webcam com relação ao display


	IEnumerator Start() {
        yield return Application.RequestUserAuthorization(UserAuthorization.WebCam | UserAuthorization.Microphone);
        if( Application.HasUserAuthorization(UserAuthorization.WebCam | UserAuthorization.Microphone) ){
			StartWebcam();
        }
    }


	/*
		StartWebcam
		Inicializa a webcam e texturas
	 */
	void StartWebcam(){
		webcamTexture = new WebCamTexture(426, 240, 30);
        webcamTexture.Play();

		Debug.Log(webcamTexture.width+"x"+webcamTexture.height);

		blendTexture = new Texture2D( webcamTexture.width, webcamTexture.height );

		if( Display ){
			Display.texture = blendTexture;
			scale = webcamTexture.width / Display.rectTransform.rect.width;
		}

		initialized = true;
	}


	/*
		UPDATE
		Todo frame calcula a diferença de frames e atualiza a textura
	 */
	void Update(){
		// Aguarda inicialização e inicializa variaveis
		if( !initialized || webcamTexture.width == 0 ) return;
		if( lastData == null ){
			lastData = webcamTexture.GetPixels32();
			blendData = new Color32[ lastData.Length ];
			checkData = new Color32[ lastData.Length ];
			for(int i=0; i<lastData.Length; i++){
				blendData[i] = new Color32(0,0,0,0);
				checkData[i] = new Color32(0,0,0,0);
			}
		}

		Difference();

		// Pula frames identicos (fps)
		if( diffsum == 0 ){
			if( nullCount++ < 5 ) return;
		}
		else nullCount = 0;


		// Atualiza textura e vetor de checagem
		for(int i=0; i<blendData.Length; i++){
			checkData[i] = blendData[i];
		}

		blendTexture.SetPixels32( blendData );
		blendTexture.Apply();
	}


	/*
		DIFFERENCE
		Calcula a diferença entre o frame atual e o frame anterior
		Coloca a diferença em blendData
	*/
	void Difference(){
		Color32[] actualData = webcamTexture.GetPixels32();
		diffsum = 0;

		for(int i=0, len=actualData.Length; i<len; i++){
			int a = ( (actualData[i].r + actualData[i].g + actualData[i].b) / 3) - 
				( (lastData[i].r + lastData[i].g + lastData[i].b) / 3);

			if( (a^a>>31)-(a>>31) > threshold ){
				blendData[i] = blendColor;
				diffsum += 1;
			}
			else{
				blendData[i] = new Color(0, 0, 0, 0);
			}
		}

		lastData = actualData;
	}


	/*
		CHECKAREA
		Checa se há interação em uma região da webcam
		retorna true ou false
	 */
	public bool checkArea( int x, int y, int width, int height ){
		if( !initialized || checkData == null ) return false;
		
		int sum = 0;
		for(int i=0; i<width*height; i++){
			int tx = x + i%width;
				tx = webcamTexture.width - tx;
			int ty = y + (int)Mathf.Floor(i/width);
				ty = webcamTexture.height - ty;
			int p = (webcamTexture.width * ty) + tx;
			sum += (checkData[p].a > 0) ? 1 : 0;
		}

		float d = ((float) sum)/((float) (width*height));
		
		return ( d > density );
	}

}