<commit_before>#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>

/*****************************************************************************************************************************/
//Namespaces
using namespace cv;
using namespace cv::ml;
using std::cout;
using std::endl;

/*****************************************************************************************************************************/
//Global
const std::string IMAGETYPE = ".jpg";              //Image type for all images inside the program
const unsigned int NUMBEROFCLASSES = 2;			   //Number of classes used in the Training
const unsigned int NUMBEROFIMAGESPERCLASS =10;     //Number of Images in each class
const unsigned int IMAGERESOLUTION = 256;          //Y and X resolution for all images

/*****************************************************************************************************************************/
//Headers
Mat resizeTo1xN(Mat image);
Mat populateTrainingMat(const unsigned int numberOfImages, const unsigned int numberOfClasses);
Mat populateLabels(const unsigned int numberOfImages, const unsigned int numberOfClasses);
void printSupportVectors(Ptr<SVM> svm);
Mat edgeDetection(Mat image);
/*****************************************************************************************************************************/
//Main
auto main(int argc, char *argv[]) -> int {
	Mat testImage;
	if (argc>1){
		std::string image = argv[1];
		testImage = imread(image.c_str(),IMREAD_GRAYSCALE);
		if (!testImage.data){
			cout<<"Error opening the image!";
			return (0);
		}
		cout<<"Parameters: "<<"extension: "<<IMAGETYPE<<" Nclasses: "<<NUMBEROFCLASSES<<" Nimages: "<<NUMBEROFIMAGESPERCLASS<<" Resolution: "<<IMAGERESOLUTION<<endl;
	}
	else {
		cout<<"Please, specify the test image!";
		return(0);
	}

	Mat sampleImage = resizeTo1xN(edgeDetection(testImage));
	sampleImage.convertTo(sampleImage,CV_32F);
	Mat trainingMatrix = populateTrainingMat(NUMBEROFIMAGESPERCLASS,NUMBEROFCLASSES);
	Mat labels=populateLabels(NUMBEROFIMAGESPERCLASS,NUMBEROFCLASSES);
	cout<<"Train data"<<endl<<"rows: "<<trainingMatrix.rows<<" cols: "<<trainingMatrix.cols<<endl<<endl;
	cout<<"Labels"<<endl<<"rows: "<<labels.rows<<" cols: "<<labels.cols<<endl<<endl;
	cout<<"Prediction Image"<<endl<<"rows: "<<sampleImage.rows<<" cols: "<<sampleImage.cols<<endl<<endl;

    // Set up SVM's parameters
    cout<<"Setting up SVM's parameters.";
    Ptr<SVM> svm = SVM::create();
    svm->setType(SVM::C_SVC );
    svm->setKernel(SVM::LINEAR);
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, 1e-6));
    cout<<"..Done!"<<endl;

    // Train the SVM with given parameters
    Ptr<TrainData> td = TrainData::create(trainingMatrix, ROW_SAMPLE, labels);
    cout<<"Training SVM.";
    svm->train(td);
    cout<<"..Done!"<<endl<<endl;

    // Train the SVM with optimal parameters
    //svm->trainAuto(td);

    float response = svm->predict(sampleImage);
    cout<<"The test image belongs to class: "<<response<<endl;

    //printSupportVectors(svm);

    waitKey(0);
}

/******************************************************************************************************************************/
Mat resizeTo1xN(Mat image){
	/* This function resize the given image into a 1xN Mat
	 * @param Mat image - The image to be resized
	 */
	Size size(IMAGERESOLUTION,IMAGERESOLUTION);
	resize(image,image,size);
	Size size1xN(image.cols*image.rows,1);
	resize(image,image,size1xN);
	return image;

}
/*****************************************************************************************************************************/
Mat populateTrainingMat(const unsigned int numberOfImages, const unsigned int numberOfClasses){
	/*Build the trainig Matrix for the the SVM. Each line will be a image.
	 * @param  const unsigned int numberOfImages
	 * @param const unsigned int numberOfClasses
	 *
	 */
	Mat trainingMatrix = Mat::zeros(numberOfClasses*numberOfImages,IMAGERESOLUTION*IMAGERESOLUTION,CV_32F);
	for (unsigned int i=0; i<numberOfClasses;i++){
		for (unsigned int j=0 ; j<numberOfImages;j++){
			const unsigned int imageNumber = j+(numberOfImages*i);
			std::ostringstream ss;
			ss<<imageNumber;                                                       // Workaround for std::to_string MinGW bug
			cv::String imageName =  ss.str() + IMAGETYPE;
 			Mat input=imread(imageName ,IMREAD_GRAYSCALE);
 			input=edgeDetection(input);
 			Mat resizedInput=resizeTo1xN(input);
			resizedInput.copyTo(trainingMatrix(Rect(0,j+(numberOfImages*i),resizedInput.cols,resizedInput.rows)));
		}
	}
	return trainingMatrix;
}

/*****************************************************************************************************************************/
Mat edgeDetection(Mat image){
	/*Uses the SobelFeldman operator to extract the image edges
			 * @param  Mat image - The image to be processed
			 *
			 */
	 int scale = 1;
	 int delta = 0;
	 int ddepth = CV_32F;
	 Mat gradX, gradY;
	 Mat absGradX, absGradY;

	 // Gradient X
	 Sobel( image, gradX, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
	 convertScaleAbs( gradX, absGradX );

	 // Gradient Y
	 Sobel( image, gradY, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
	 convertScaleAbs( gradY, absGradY );

	 // Total Gradient (approximate)
	 addWeighted( absGradX, 0.5, absGradY, 0.5, 0, image );
	 return image;
}

/*****************************************************************************************************************************/
Mat populateLabels(const unsigned int numberOfImages, const unsigned int numberOfClasses){
	/*Build the trainig Matrix's Labels for the the SVM. Each line will be the label of the respective image in the TrainingMat.
		 * @param  const unsigned int numberOfImages
		 * @param const unsigned int numberOfClasses
		 *
		 */
	std::vector<int> labels;
	for (unsigned int i=0; i<numberOfClasses;i++){
			for (unsigned int j=0 ; j<numberOfImages;j++){
				labels.push_back(i);
			}
	}
	Mat labelsMat(numberOfImages*numberOfClasses, 1, CV_32SC1 , labels.data());
	return labelsMat;

}

/*****************************************************************************************************************************/
void printSupportVectors(Ptr<SVM> svm){
	/* Print the Support Vectors.
	 * @param Ptr<SVM> svm The svm containing the Support Vectors to show
	 */
	// Data for visual representation
	int width = 512, height = 512;
	Mat image = Mat::zeros(height, width, CV_8UC3);
	int thickness = -1;
	int lineType = 8;
	// Show support vectors
	thickness = 2;
	lineType  = 8;
	Mat sv = svm->getUncompressedSupportVectors();
	for (int i = 0; i < sv.rows; ++i){
		const float* v = sv.ptr<float>(i);
		circle( image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(30, 128, 0), thickness, lineType);
	}
	imwrite("result.png", image);
	imshow("Uncompressed Support Vectors", image);

}
/*****************************************************************************************************************************/
<commit_msg>printSupportVectors parameter tweaking<commit_after>#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>

/*****************************************************************************************************************************/
//Namespaces
using namespace cv;
using namespace cv::ml;
using std::cout;
using std::endl;

/*****************************************************************************************************************************/
//Global
const std::string IMAGETYPE = ".jpg";              //Image type for all images inside the program
const unsigned int NUMBEROFCLASSES = 2;			   //Number of classes used in the Training
const unsigned int NUMBEROFIMAGESPERCLASS =10;     //Number of Images in each class
const unsigned int IMAGERESOLUTION = 256;          //Y and X resolution for all images

/*****************************************************************************************************************************/
//Headers
Mat resizeTo1xN(Mat image);
Mat populateTrainingMat(const unsigned int numberOfImages, const unsigned int numberOfClasses);
Mat populateLabels(const unsigned int numberOfImages, const unsigned int numberOfClasses);
void printSupportVectors(const Ptr<SVM>& svm);
Mat edgeDetection(Mat image);
/*****************************************************************************************************************************/
//Main
auto main(int argc, char *argv[]) -> int {
	Mat testImage;
	if (argc>1){
		std::string image = argv[1];
		testImage = imread(image.c_str(),IMREAD_GRAYSCALE);
		if (!testImage.data){
			cout<<"Error opening the image!";
			return (0);
		}
		cout<<"Parameters: "<<"extension: "<<IMAGETYPE<<" Nclasses: "<<NUMBEROFCLASSES<<" Nimages: "<<NUMBEROFIMAGESPERCLASS<<" Resolution: "<<IMAGERESOLUTION<<endl;
	}
	else {
		cout<<"Please, specify the test image!";
		return(0);
	}

	Mat sampleImage = resizeTo1xN(edgeDetection(testImage));
	sampleImage.convertTo(sampleImage,CV_32F);
	Mat trainingMatrix = populateTrainingMat(NUMBEROFIMAGESPERCLASS,NUMBEROFCLASSES);
	Mat labels=populateLabels(NUMBEROFIMAGESPERCLASS,NUMBEROFCLASSES);
	cout<<"Train data"<<endl<<"rows: "<<trainingMatrix.rows<<" cols: "<<trainingMatrix.cols<<endl<<endl;
	cout<<"Labels"<<endl<<"rows: "<<labels.rows<<" cols: "<<labels.cols<<endl<<endl;
	cout<<"Prediction Image"<<endl<<"rows: "<<sampleImage.rows<<" cols: "<<sampleImage.cols<<endl<<endl;

    // Set up SVM's parameters
    cout<<"Setting up SVM's parameters.";
    Ptr<SVM> svm = SVM::create();
    svm->setType(SVM::C_SVC );
    svm->setKernel(SVM::LINEAR);
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 10000, 1e-6));
    cout<<"..Done!"<<endl;

    // Train the SVM with given parameters
    Ptr<TrainData> td = TrainData::create(trainingMatrix, ROW_SAMPLE, labels);
    cout<<"Training SVM.";
    svm->train(td);
    cout<<"..Done!"<<endl<<endl;

    // Train the SVM with optimal parameters
    //svm->trainAuto(td);

    float response = svm->predict(sampleImage);
    cout<<"The test image belongs to class: "<<response<<endl;

    printSupportVectors(svm);

    waitKey(0);
}

/******************************************************************************************************************************/
Mat resizeTo1xN(Mat image){
	/* This function resize the given image into a 1xN Mat
	 * @param Mat image - The image to be resized
	 */
	Size size(IMAGERESOLUTION,IMAGERESOLUTION);
	resize(image,image,size);
	Size size1xN(image.cols*image.rows,1);
	resize(image,image,size1xN);
	return image;

}
/*****************************************************************************************************************************/
Mat populateTrainingMat(const unsigned int numberOfImages, const unsigned int numberOfClasses){
	/*Build the trainig Matrix for the the SVM. Each line will be a image.
	 * @param  const unsigned int numberOfImages
	 * @param const unsigned int numberOfClasses
	 *
	 */
	Mat trainingMatrix = Mat::zeros(numberOfClasses*numberOfImages,IMAGERESOLUTION*IMAGERESOLUTION,CV_32F);
	for (unsigned int i=0; i<numberOfClasses;i++){
		for (unsigned int j=0 ; j<numberOfImages;j++){
			const unsigned int imageNumber = j+(numberOfImages*i);
			std::ostringstream ss;
			ss<<imageNumber;                                                       // Workaround for std::to_string MinGW bug
			cv::String imageName =  ss.str() + IMAGETYPE;
 			Mat input=imread(imageName ,IMREAD_GRAYSCALE);
 			input=edgeDetection(input);
 			Mat resizedInput=resizeTo1xN(input);
			resizedInput.copyTo(trainingMatrix(Rect(0,j+(numberOfImages*i),resizedInput.cols,resizedInput.rows)));
		}
	}
	return trainingMatrix;
}

/*****************************************************************************************************************************/
Mat edgeDetection(Mat image){
	/*Uses the SobelFeldman operator to extract the image edges
			 * @param  Mat image - The image to be processed
			 *
			 */
	 int scale = 1;
	 int delta = 0;
	 int ddepth = CV_32F;
	 Mat gradX, gradY;
	 Mat absGradX, absGradY;

	 // Gradient X
	 Sobel( image, gradX, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
	 convertScaleAbs( gradX, absGradX );

	 // Gradient Y
	 Sobel( image, gradY, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
	 convertScaleAbs( gradY, absGradY );

	 // Total Gradient (approximate)
	 addWeighted( absGradX, 0.5, absGradY, 0.5, 0, image );
	 return image;
}

/*****************************************************************************************************************************/
Mat populateLabels(const unsigned int numberOfImages, const unsigned int numberOfClasses){
	/*Build the trainig Matrix's Labels for the the SVM. Each line will be the label of the respective image in the TrainingMat.
		 * @param  const unsigned int numberOfImages
		 * @param const unsigned int numberOfClasses
		 *
		 */
	std::vector<int> labels;
	for (unsigned int i=0; i<numberOfClasses;i++){
			for (unsigned int j=0 ; j<numberOfImages;j++){
				labels.push_back(i);
			}
	}
	Mat labelsMat(numberOfImages*numberOfClasses, 1, CV_32SC1 , labels.data());
	return labelsMat;

}

/*****************************************************************************************************************************/
void printSupportVectors(const Ptr<SVM>& svm){
	/* Print the Support Vectors.
	 * @param Ptr<SVM> svm The svm containing the Support Vectors to show
	 */
	// Data for visual representation
	int width = 512, height = 512;
	Mat image = Mat::zeros(height, width, CV_8UC3);
	int thickness = -1;
	int lineType = 8;
	// Show support vectors
	thickness = 2;
	lineType  = 8;
	Mat sv = svm->getUncompressedSupportVectors();
	for (int i = 0; i < sv.rows; ++i){
		const float* v = sv.ptr<float>(i);
		circle( image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(30, 128, 0), thickness, lineType);
	}
	imwrite("result.png", image);
	imshow("Uncompressed Support Vectors", image);

}
/*****************************************************************************************************************************/
<|endoftext|>


<commit_before>// OPCServer.cpp
// CinderOpenPixelControlSandbox
//
// Created by Eric Mika on 12/23/15.

#include "OpcServer.h"

#include "CinderAsio.h"
#include "cinder/Cinder.h"
#include "cinder/Log.h"

#include "cinder/Utilities.h"
#include "cinder/app/App.h"

using namespace kp::opc;

#pragma mark Lifecycle

ServerRef Server::create(int numLeds, int32_t port, ColorOrder colorOrder) {
	return ServerRef(new Server(numLeds, port, colorOrder))->shared_from_this();
}

Server::Server(int numLeds, int32_t port, ColorOrder colorOrder) {
	CI_LOG_V("Client Created");
	mNumLeds = numLeds;
	mPort = port;
	mColorOrder = colorOrder;
	mNumMessagesReceived = 0;

	// Temp set size... preliminary channel support
	mChannels.resize(1);
	mChannels[0].resize(mNumLeds);

	mTcpServer = TcpServer::create(ci::app::App::get()->io_service());

	// Add callbacks to work with the server asynchronously.
	mTcpServer->connectAcceptEventHandler(&Server::onAccept, this);
	mTcpServer->connectCancelEventHandler(&Server::onCancel, this);
	mTcpServer->connectErrorEventHandler(&Server::onError, this);

	accept();
}

Server::~Server() {
	CI_LOG_V("Client Destroyed");

	// clean up queue
	mBufferQueue.clear();

	mTcpServer->cancel();
}

#pragma mark Networking

void Server::accept() {
	// CI_LOG_V("Accept");

	if (mTcpSession) {
		mTcpSession.reset();
	}

	// Start listening
	if (mTcpServer) {
		mTcpServer->accept(static_cast<uint16_t>(mPort));
		// CI_LOG_V("Listening on port: " << mPort);
	}
}

#pragma mark Networking Callbacks

void Server::onAccept(TcpSessionRef session) {
	// CI_LOG_V("Connected");

	// Get the session from the argument and set callbacks.
	mTcpSession = session;
	mTcpSession->connectCloseEventHandler(&Server::onClose, this);
	mTcpSession->connectErrorEventHandler(&Server::onError, this);
	mTcpSession->connectReadEventHandler(&Server::onRead, this);
	mTcpSession->connectReadCompleteEventHandler(&Server::onReadComplete, this);

	// Start reading data from the client.
	mTcpSession->read();
}

void Server::onRead(ci::BufferRef buffer) {
	// See http://openpixelcontrol.org for spec.
	// Note that support for multiple channels is not implemented.

	// Enqueue received message
	const uint8_t *data = static_cast<const uint8_t *>(buffer->getData());
	for (int i = 0; i < buffer->getSize(); i++) {
		mBufferQueue.push_back(data[i]);
	}

	// Parse if possible
	bool isMoreToParse = true;
	while (isMoreToParse) {
		isMoreToParse = parseQueue(mBufferQueue);
	}

	// Read next message
	mTcpSession->read();
}

bool Server::parseQueue(std::deque<uint8_t> &queue) {

	// Validate the queue
	if (queue.size() < HEADER_LENGTH) {
		// CI_LOG_E("Received OPC message with length: " << queue.size() << " Too short.");
		return false;
	}

	// Peek into the queue
	const uint8_t channel = queue[0];													 // 0 is broadcast to all channels
	const uint8_t command = queue[1];													 // 0 is set pixel color
	const uint16_t ledDataLength = (queue[2] << 8) | queue[3]; //
	const int numLeds = ledDataLength / BYTES_PER_LED;
	const int expectedLength = HEADER_LENGTH + ledDataLength;

	if (queue.size() < expectedLength) {
		// CI_LOG_E("OPC message too short. Expected length: " << static_cast<int>(expectedLength) << "\tReceived length: " << queue.size());
		return false;
	}

	if (command != 0) {
		CI_LOG_E("OPC message has unsupported command type: " << static_cast<int>(command));
	} else if (channel != 0) {
		CI_LOG_E("OPC message was for channel: " << static_cast<int>(channel) << " Cinder OPC Block does not currently support multiple channels.");
	} else {
		// Everything looks ok, read the data off the front
		mNumMessagesReceived++;

		// CI_LOG_V("Channel: " << static_cast<int>(channel) << "\tCommand: " << static_cast<int>(command) << "\tLength: " << length);

		// Set the model from the data
		const int *colorOrder = &(COLOR_ORDER_LOOKUP[mColorOrder][0]);

		for (int i = 0; i < numLeds; i++) {
			const int ledIndex = HEADER_LENGTH + (i * BYTES_PER_LED);

			for (int k = 0; k < 3; k++) {
				mChannels[channel][i][colorOrder[k]] = queue[ledIndex + k] / 255.0;
			}
		}
	}

	// Clear what we read from the queue
	queue.erase(queue.begin(), queue.begin() + expectedLength);
	return true;
}

void Server::onReadComplete() {
	// CI_LOG_V("On Read complete");
	accept();
}

void Server::onError(std::string err, size_t bytesTransferred) {
	CI_LOG_V("Error" + (err.empty() ? "" : (": " + err)););
}

void Server::onClose() {
	// CI_LOG_V("On Close");
}

void Server::onCancel() {
	// CI_LOG_V("On Cancel");
}

const std::vector<ci::Color> Server::getLeds() const {
	return mChannels[0];
}

const unsigned long Server::getNumMessagesReceived() {
	return mNumMessagesReceived;
}
<commit_msg>Handle long messages.<commit_after>// OPCServer.cpp
// CinderOpenPixelControlSandbox
//
// Created by Eric Mika on 12/23/15.

#include "OpcServer.h"

#include "CinderAsio.h"
#include "cinder/Cinder.h"
#include "cinder/Log.h"

#include "cinder/Utilities.h"
#include "cinder/app/App.h"

using namespace kp::opc;

#pragma mark Lifecycle

ServerRef Server::create(int numLeds, int32_t port, ColorOrder colorOrder) {
	return ServerRef(new Server(numLeds, port, colorOrder))->shared_from_this();
}

Server::Server(int numLeds, int32_t port, ColorOrder colorOrder) {
	CI_LOG_V("Client Created");
	mNumLeds = numLeds;
	mPort = port;
	mColorOrder = colorOrder;
	mNumMessagesReceived = 0;

	// Temp set size... preliminary channel support
	mChannels.resize(1);
	mChannels[0].resize(mNumLeds);

	mTcpServer = TcpServer::create(ci::app::App::get()->io_service());

	// Add callbacks to work with the server asynchronously.
	mTcpServer->connectAcceptEventHandler(&Server::onAccept, this);
	mTcpServer->connectCancelEventHandler(&Server::onCancel, this);
	mTcpServer->connectErrorEventHandler(&Server::onError, this);

	accept();
}

Server::~Server() {
	CI_LOG_V("Client Destroyed");

	// clean up queue
	mBufferQueue.clear();

	mTcpServer->cancel();
}

#pragma mark Networking

void Server::accept() {
	// CI_LOG_V("Accept");

	if (mTcpSession) {
		mTcpSession.reset();
	}

	// Start listening
	if (mTcpServer) {
		mTcpServer->accept(static_cast<uint16_t>(mPort));
		// CI_LOG_V("Listening on port: " << mPort);
	}
}

#pragma mark Networking Callbacks

void Server::onAccept(TcpSessionRef session) {
	// CI_LOG_V("Connected");

	// Get the session from the argument and set callbacks.
	mTcpSession = session;
	mTcpSession->connectCloseEventHandler(&Server::onClose, this);
	mTcpSession->connectErrorEventHandler(&Server::onError, this);
	mTcpSession->connectReadEventHandler(&Server::onRead, this);
	mTcpSession->connectReadCompleteEventHandler(&Server::onReadComplete, this);

	// Start reading data from the client.
	mTcpSession->read();
}

void Server::onRead(ci::BufferRef buffer) {
	// See http://openpixelcontrol.org for spec.
	// Note that support for multiple channels is not implemented.

	// Enqueue received message
	const uint8_t *data = static_cast<const uint8_t *>(buffer->getData());
	for (int i = 0; i < buffer->getSize(); i++) {
		mBufferQueue.push_back(data[i]);
	}

	// Parse if possible
	bool isMoreToParse = true;
	while (isMoreToParse) {
		isMoreToParse = parseQueue(mBufferQueue);
	}

	// Read next message
	mTcpSession->read();
}

bool Server::parseQueue(std::deque<uint8_t> &queue) {

	// Validate the queue
	if (queue.size() < HEADER_LENGTH) {
		// CI_LOG_E("Received OPC message with length: " << queue.size() << " Too short.");
		return false;
	}

	// Peek into the queue
	const uint8_t channel = queue[0];													 // 0 is broadcast to all channels
	const uint8_t command = queue[1];													 // 0 is set pixel color
	const uint16_t ledDataLength = (queue[2] << 8) | queue[3]; //
	const int numLedsReceived = ledDataLength / BYTES_PER_LED;
	const int expectedLength = HEADER_LENGTH + ledDataLength;

	if (queue.size() < expectedLength) {
		// CI_LOG_E("OPC message too short. Expected length: " << static_cast<int>(expectedLength) << "\tReceived length: " << queue.size());
		return false;
	}

	if (numLedsReceived > mNumLeds) {
		// CI_LOG_W("Received data for " << numLedsReceived << " but server only set up to represent " << mNumLeds << " leds.");
		// We just discard any extras...
	}

	if (command != 0) {
		CI_LOG_E("OPC message has unsupported command type: " << static_cast<int>(command));
	} else if (channel != 0) {
		CI_LOG_E("OPC message was for channel: " << static_cast<int>(channel) << " Cinder OPC Block does not currently support multiple channels.");
	} else {
		// Everything looks ok, read the data off the front
		mNumMessagesReceived++;

		// CI_LOG_V("Channel: " << static_cast<int>(channel) << "\tCommand: " << static_cast<int>(command) << "\tLength: " << length);

		// Set the model from the data
		const int *colorOrder = &(COLOR_ORDER_LOOKUP[mColorOrder][0]);

		for (int i = 0; i < mNumLeds; i++) {
			const int ledIndex = HEADER_LENGTH + (i * BYTES_PER_LED);

			for (int k = 0; k < 3; k++) {
				mChannels[channel][i][colorOrder[k]] = queue[ledIndex + k] / 255.0;
			}
		}
	}

	// Clear what we read from the queue
	queue.erase(queue.begin(), queue.begin() + expectedLength);
	return true;
}

void Server::onReadComplete() {
	// CI_LOG_V("On Read complete");
	accept();
}

void Server::onError(std::string err, size_t bytesTransferred) {
	CI_LOG_V("Error" + (err.empty() ? "" : (": " + err)););
}

void Server::onClose() {
	// CI_LOG_V("On Close");
}

void Server::onCancel() {
	// CI_LOG_V("On Cancel");
}

const std::vector<ci::Color> Server::getLeds() const {
	return mChannels[0];
}

const unsigned long Server::getNumMessagesReceived() {
	return mNumMessagesReceived;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <stdio.h>
#include <pthread.h>
#include <zlib.h>
#include <png.h>
#include "LPType.h"
#include "PNGWriter.h"
#include "PaletteOptimizer.h"

struct parameter
{
    int type;
    int strategy;
    int window_bits;
    int filter;

    void print(size_t size)
    {
        static const char* strategy_str[] = {
            "Z_DEFAULT_STRATEGY",
            "Z_FILTERED",
            "Z_HUFFMAN_ONLY",
            "Z_RLE"
        };
        static const char* filter_str[] = {
            "PNG_FILTER_NONE",
            "PNG_FILTER_SUB",
            "PNG_FILTER_UP",
            "PNG_FILTER_AVG",
            "PNG_FILTER_PAETH",
            "PNG_ALL_FILTERS"
        };
        if (type == 0)
        {
            std::cout << size << " bytes (compressor: zLib, strategy: " << strategy_str[strategy] << ", filter: "
                      << filter_str[filter] << ")" << std::endl;
        }
        else
        {
            std::cout << size << " bytes (compressor: zopfli, filter: " << filter_str[filter] << ")" << std::endl;
                  }
    }
    int get_type() const { return type; }
    int get_strategy() const { return strategy; }
    int get_window_bits() const { return window_bits; }
    int get_filter() const
    {
        static const int filters[] = {
            PNG_FILTER_NONE,
            PNG_FILTER_SUB,
            PNG_FILTER_UP,
            PNG_FILTER_AVG,
            PNG_FILTER_PAETH,
            PNG_ALL_FILTERS
        };
        return filters[filter];
    }
};

const int total_parameter = 30;

parameter parameters[total_parameter] = {
    { 1, 0, 15, 0 },
    { 1, 0, 15, 1 },
    { 1, 0, 15, 2 },
    { 1, 0, 15, 3 },
    { 1, 0, 15, 4 },
    { 1, 0, 15, 5 },
    { 0, 0, 15, 0 },
    { 0, 0, 15, 1 },
    { 0, 0, 15, 2 },
    { 0, 0, 15, 3 },
    { 0, 0, 15, 4 },
    { 0, 0, 15, 5 },
    { 0, 1, 15, 0 },
    { 0, 1, 15, 1 },
    { 0, 1, 15, 2 },
    { 0, 1, 15, 3 },
    { 0, 1, 15, 4 },
    { 0, 1, 15, 5 },
    { 0, 2, 15, 0 },
    { 0, 2, 15, 1 },
    { 0, 2, 15, 2 },
    { 0, 2, 15, 3 },
    { 0, 2, 15, 4 },
    { 0, 2, 15, 5 },
    { 0, 3, 15, 0 },
    { 0, 3, 15, 1 },
    { 0, 3, 15, 2 },
    { 0, 3, 15, 3 },
    { 0, 3, 15, 4 },
    { 0, 3, 15, 5 }
};

struct Chunk
{
    unsigned char* buffer;
    size_t size;
};

class Buffer
{
public:
    Buffer() : _totalsize(0) {}
    ~Buffer() {
        std::vector<Chunk>::iterator i;
        for (i = chunks_.begin(); i != chunks_.end(); ++i)
        {
            delete[] (*i).buffer;
        }
    }

    size_t size() const
    {
        return _totalsize;
    }

    void write(png_bytep data, png_size_t length)
    {
        Chunk chunk;
        chunk.buffer = new png_byte[length];
        memcpy(chunk.buffer, data, length);
        chunk.size = length;
        chunks_.push_back(chunk);
        _totalsize += length;
    }

    void flush(unsigned char*& destination, size_t& filesize) const
    {
        destination = new png_byte[_totalsize];
        size_t offset = 0;
        std::vector<Chunk>::const_iterator i;
        for (i = chunks_.begin(); i != chunks_.end(); ++i)
        {
            memcpy(destination + offset, (*i).buffer, (*i).size);
            offset += (*i).size;
        }
        filesize = _totalsize;
    }

private:
    std::vector<Chunk> chunks_;
    size_t _totalsize;
};

class MultithreadTask
{
public:
    MultithreadTask(PNGWriter* writer, bool verbose)
        : _next_task(0), _best_size(1 << 31), _best_index(-1), _writer(writer),
          _best_result(0), _verbose(verbose)
    {
        pthread_mutex_init(&_mutex, NULL);
    }
    ~MultithreadTask()
    {
        pthread_mutex_destroy(&_mutex);
        if (_best_result)
        {
            delete _best_result;
        }
    }
    int get_next()
    {
        int result;
        pthread_mutex_lock(&_mutex);
        if (_next_task < total_parameter)
        {
            result = _next_task++;
        }
        else
        {
            result = -1;
        }
        pthread_mutex_unlock(&_mutex);
        return result;
    }
    void store_result(Buffer* buffer, size_t index)
    {
        pthread_mutex_lock(&_mutex);
        if (buffer->size() < _best_size)
        {
            _best_size = buffer->size();
            _best_index = index;
            if (_best_result)
            {
                delete _best_result;
            }
            _best_result = buffer;
        }
        if (_verbose)
        {
            parameter* param = parameters + index;
            param->print(buffer->size());
        }
        pthread_mutex_unlock(&_mutex);
    }
    size_t best_size() const { return _best_size; }
    int best_index() const { return _best_index; }
    void flush(unsigned char*& file_content, size_t& filesize) const {
        if (_best_result)
        {
            _best_result->flush(file_content, filesize);
        }
    }
    static void* thread_main(void* param);

private:
    pthread_mutex_t _mutex;
    int _next_task;
    size_t _best_size;
    int _best_index;
    PNGWriter* _writer;
    Buffer* _best_result;
    bool _verbose;
};

void* MultithreadTask::thread_main(void* param)
{
    MultithreadTask* self = reinterpret_cast<MultithreadTask*>(param);
    int parameter_index = self->get_next();
    while (parameter_index != -1)
    {
        Buffer* buffer = new Buffer();
        self->_writer->compress(parameter_index, buffer);
        self->store_result(buffer, parameter_index);
        parameter_index = self->get_next();
    }
    pthread_exit(param);
}

void dummy_flash(png_structp png_ptr)
{
}

void buffer_write(png_structp png_ptr, png_bytep data, png_size_t length)
{
    Buffer* buffer = reinterpret_cast<Buffer*>(png_get_io_ptr(png_ptr));
    buffer->write(data, length);
}

PNGWriter::~PNGWriter()
{
}

void PNGWriter::process(buffer_t raw_buffer)
{
    _raw_buffer = raw_buffer;
    _image_rows.reset(new unsigned char*[_height]);
    size_t pixelSize = (_has_alpha) ? 4 : 3;
    for (size_t i = 0; i < _height; ++i)
    {
        _image_rows[i] = raw_buffer.get() + i * _width * pixelSize;
    }
    _process();
}

void PNGWriter::process(buffer_t raw_buffer, bool shrink)
{
    if (shrink)
    {
        buffer_t buffer(new unsigned char[_width * _height * 3]);
        for (size_t y = 0; y < _height; y++)
        {
            for (size_t x = 0; x < _width; x++)
            {
                size_t offset1 = (y * _width + x) * 3;
                size_t offset2 = (y * _width + x) * 4;
                buffer[offset1]     = raw_buffer[offset2];
       	        buffer[offset1 + 1] = raw_buffer[offset2 + 1];
                buffer[offset1 + 2] = raw_buffer[offset2 + 2];
            }
        }
        process(buffer);
    }
    else
    {
        process(raw_buffer);
    }
}

void PNGWriter::process(buffer_t raw_buffer, palette_t palette, trans_t trans, bool optimize)
{
    _index = true;
    if (optimize)
    {
        PaletteOptimizer optimizer(_width, _height);
        optimizer.process8bit(raw_buffer, palette, trans);
        _raw_buffer = optimizer.buffer();
        _palette = optimizer.palette();
        _trans = optimizer.trans();
        _palette_size = optimizer.palette_size();
        _trans_size = optimizer.trans_size();
    }
    else
    {
        _raw_buffer = raw_buffer;
        _palette = palette;
        _trans = trans;
        _palette_size = 255;
        _trans_size = 255;
    }
    _image_rows.reset(new unsigned char*[_height]);
    for (size_t i = 0; i < _height; ++i)
    {
        _image_rows[i] = _raw_buffer.get() + i * _width;
    }
    _process();
}

void PNGWriter::_process()
{
    if (_optimize)
    {
        int rc;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
        MultithreadTask task(this, _verbose);
        pthread_t threads[8];
        for (size_t i = 0; i < 8; ++i)
        {
            rc = pthread_create(&threads[i], &attr, MultithreadTask::thread_main, reinterpret_cast<void*>(&task));
            if (rc)
            {
                std::cout << "pthread create error" << std::endl;
            }
        }
        for (size_t i = 0; i < 8; ++i)
        {
            void* status;
            rc = pthread_join(threads[i], &status);
            if (rc)
            {
                std::cout << "pthread join error" << std::endl;
            }
        }
        int best_index = task.best_index();
        if (best_index > -1)
        {
            if (_verbose)
            {
                std::cout << "best result: ";
                parameters[best_index].print(task.best_size());
            }
            unsigned char* content = _file_content.get();
            task.flush(content, _file_size);
            _file_content.reset(content);
            _valid = true;
        }
    }
    else
    {
        Buffer* buffer = new Buffer();
        compress(6, buffer);
        unsigned char* content = _file_content.get();
        buffer->flush(content, _file_size);
        _file_content.reset(content);
        delete buffer;
        _valid = true;
    }
}

void PNGWriter::write(const char* filepath)
{
    if (_valid)
    {
        FILE * fp = fopen(filepath, "wb");
        fwrite(_file_content.get(), 1 , _file_size , fp);
        fclose(fp);
    }
}

void PNGWriter::compress(size_t parameter_index, Buffer* buffer)
{
    png_structp png = 0;
    png_infop info = 0;
    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    if (!png)
    {
        return;
    }
    info = png_create_info_struct(png);
    if (!info)
    {
        return;
    }

    png_set_write_fn(png, reinterpret_cast<void*>(buffer), buffer_write, dummy_flash);

    parameter* param = parameters + parameter_index;
    if (param->get_type() == PNG_WRITER_USE_ZLIB)
    {
        png_set_compressor_type(png, PNG_WRITER_USE_ZLIB);
        png_set_compression_strategy(png, param->get_strategy());
        png_set_compression_window_bits(png, param->get_window_bits());
        png_set_filter(png, PNG_FILTER_TYPE_BASE, param->get_filter());
        png_set_compression_level(png, Z_BEST_COMPRESSION);
        png_set_compression_mem_level(png, MAX_MEM_LEVEL);
    }
    else // PNG_WRITER_USE_ZOPFLI
    {
        png_set_compressor_type(png, PNG_WRITER_USE_ZOPFLI);
        png_set_compression_level(png, 15);
    }
    bool packing = false;
    if (_index)
    {
        size_t bitlength = 8;
        if (_palette_size <= 2)
        {
            bitlength = 1;
            packing = true;
        }
        else if (_palette_size <= 4)
        {
            bitlength = 2;
            packing = true;
        }
        else if (_palette_size <= 16)
        {
            bitlength = 4;
            packing = true;
        }
        png_set_IHDR(png, info, _width, _height, bitlength, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
        png_set_PLTE(png, info, _palette.get(), _palette_size);
        if (_trans_size > 0)
        {
            png_set_tRNS(png, info, _trans.get(), _trans_size, NULL);
        }
    }
    else if (_has_alpha)
    {
        png_set_IHDR(png, info, _width, _height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    }
    else
    {
        png_set_IHDR(png, info, _width, _height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    }
    png_write_info(png, info);
    if (packing)
    {
        png_set_packing(png);
    }
    png_write_image(png, _image_rows.get());
    png_write_end(png, info);
};
<commit_msg>fix bug: apply filter for zopfli output<commit_after>#include <iostream>
#include <vector>
#include <stdio.h>
#include <pthread.h>
#include <zlib.h>
#include <png.h>
#include "LPType.h"
#include "PNGWriter.h"
#include "PaletteOptimizer.h"

struct parameter
{
    int type;
    int strategy;
    int window_bits;
    int filter;

    void print(size_t size)
    {
        static const char* strategy_str[] = {
            "Z_DEFAULT_STRATEGY",
            "Z_FILTERED",
            "Z_HUFFMAN_ONLY",
            "Z_RLE"
        };
        static const char* filter_str[] = {
            "PNG_FILTER_NONE",
            "PNG_FILTER_SUB",
            "PNG_FILTER_UP",
            "PNG_FILTER_AVG",
            "PNG_FILTER_PAETH",
            "PNG_ALL_FILTERS"
        };
        if (type == 0)
        {
            std::cout << size << " bytes (compressor: zLib, strategy: " << strategy_str[strategy] << ", filter: "
                      << filter_str[filter] << ")" << std::endl;
        }
        else
        {
            std::cout << size << " bytes (compressor: zopfli, filter: " << filter_str[filter] << ")" << std::endl;
                  }
    }
    int get_type() const { return type; }
    int get_strategy() const { return strategy; }
    int get_window_bits() const { return window_bits; }
    int get_filter() const
    {
        static const int filters[] = {
            PNG_FILTER_NONE,
            PNG_FILTER_SUB,
            PNG_FILTER_UP,
            PNG_FILTER_AVG,
            PNG_FILTER_PAETH,
            PNG_ALL_FILTERS
        };
        return filters[filter];
    }
};

const int total_parameter = 30;

parameter parameters[total_parameter] = {
    { 1, 0, 15, 0 },
    { 1, 0, 15, 1 },
    { 1, 0, 15, 2 },
    { 1, 0, 15, 3 },
    { 1, 0, 15, 4 },
    { 1, 0, 15, 5 },
    { 0, 0, 15, 0 },
    { 0, 0, 15, 1 },
    { 0, 0, 15, 2 },
    { 0, 0, 15, 3 },
    { 0, 0, 15, 4 },
    { 0, 0, 15, 5 },
    { 0, 1, 15, 0 },
    { 0, 1, 15, 1 },
    { 0, 1, 15, 2 },
    { 0, 1, 15, 3 },
    { 0, 1, 15, 4 },
    { 0, 1, 15, 5 },
    { 0, 2, 15, 0 },
    { 0, 2, 15, 1 },
    { 0, 2, 15, 2 },
    { 0, 2, 15, 3 },
    { 0, 2, 15, 4 },
    { 0, 2, 15, 5 },
    { 0, 3, 15, 0 },
    { 0, 3, 15, 1 },
    { 0, 3, 15, 2 },
    { 0, 3, 15, 3 },
    { 0, 3, 15, 4 },
    { 0, 3, 15, 5 }
};

struct Chunk
{
    unsigned char* buffer;
    size_t size;
};

class Buffer
{
public:
    Buffer() : _totalsize(0) {}
    ~Buffer() {
        std::vector<Chunk>::iterator i;
        for (i = chunks_.begin(); i != chunks_.end(); ++i)
        {
            delete[] (*i).buffer;
        }
    }

    size_t size() const
    {
        return _totalsize;
    }

    void write(png_bytep data, png_size_t length)
    {
        Chunk chunk;
        chunk.buffer = new png_byte[length];
        memcpy(chunk.buffer, data, length);
        chunk.size = length;
        chunks_.push_back(chunk);
        _totalsize += length;
    }

    void flush(unsigned char*& destination, size_t& filesize) const
    {
        destination = new png_byte[_totalsize];
        size_t offset = 0;
        std::vector<Chunk>::const_iterator i;
        for (i = chunks_.begin(); i != chunks_.end(); ++i)
        {
            memcpy(destination + offset, (*i).buffer, (*i).size);
            offset += (*i).size;
        }
        filesize = _totalsize;
    }

private:
    std::vector<Chunk> chunks_;
    size_t _totalsize;
};

class MultithreadTask
{
public:
    MultithreadTask(PNGWriter* writer, bool verbose)
        : _next_task(0), _best_size(1 << 31), _best_index(-1), _writer(writer),
          _best_result(0), _verbose(verbose)
    {
        pthread_mutex_init(&_mutex, NULL);
    }
    ~MultithreadTask()
    {
        pthread_mutex_destroy(&_mutex);
        if (_best_result)
        {
            delete _best_result;
        }
    }
    int get_next()
    {
        int result;
        pthread_mutex_lock(&_mutex);
        if (_next_task < total_parameter)
        {
            result = _next_task++;
        }
        else
        {
            result = -1;
        }
        pthread_mutex_unlock(&_mutex);
        return result;
    }
    void store_result(Buffer* buffer, size_t index)
    {
        pthread_mutex_lock(&_mutex);
        if (buffer->size() < _best_size)
        {
            _best_size = buffer->size();
            _best_index = index;
            if (_best_result)
            {
                delete _best_result;
            }
            _best_result = buffer;
        }
        if (_verbose)
        {
            parameter* param = parameters + index;
            param->print(buffer->size());
        }
        pthread_mutex_unlock(&_mutex);
    }
    size_t best_size() const { return _best_size; }
    int best_index() const { return _best_index; }
    void flush(unsigned char*& file_content, size_t& filesize) const {
        if (_best_result)
        {
            _best_result->flush(file_content, filesize);
        }
    }
    static void* thread_main(void* param);

private:
    pthread_mutex_t _mutex;
    int _next_task;
    size_t _best_size;
    int _best_index;
    PNGWriter* _writer;
    Buffer* _best_result;
    bool _verbose;
};

void* MultithreadTask::thread_main(void* param)
{
    MultithreadTask* self = reinterpret_cast<MultithreadTask*>(param);
    int parameter_index = self->get_next();
    while (parameter_index != -1)
    {
        Buffer* buffer = new Buffer();
        self->_writer->compress(parameter_index, buffer);
        self->store_result(buffer, parameter_index);
        parameter_index = self->get_next();
    }
    pthread_exit(param);
}

void dummy_flash(png_structp png_ptr)
{
}

void buffer_write(png_structp png_ptr, png_bytep data, png_size_t length)
{
    Buffer* buffer = reinterpret_cast<Buffer*>(png_get_io_ptr(png_ptr));
    buffer->write(data, length);
}

PNGWriter::~PNGWriter()
{
}

void PNGWriter::process(buffer_t raw_buffer)
{
    _raw_buffer = raw_buffer;
    _image_rows.reset(new unsigned char*[_height]);
    size_t pixelSize = (_has_alpha) ? 4 : 3;
    for (size_t i = 0; i < _height; ++i)
    {
        _image_rows[i] = raw_buffer.get() + i * _width * pixelSize;
    }
    _process();
}

void PNGWriter::process(buffer_t raw_buffer, bool shrink)
{
    if (shrink)
    {
        buffer_t buffer(new unsigned char[_width * _height * 3]);
        for (size_t y = 0; y < _height; y++)
        {
            for (size_t x = 0; x < _width; x++)
            {
                size_t offset1 = (y * _width + x) * 3;
                size_t offset2 = (y * _width + x) * 4;
                buffer[offset1]     = raw_buffer[offset2];
       	        buffer[offset1 + 1] = raw_buffer[offset2 + 1];
                buffer[offset1 + 2] = raw_buffer[offset2 + 2];
            }
        }
        process(buffer);
    }
    else
    {
        process(raw_buffer);
    }
}

void PNGWriter::process(buffer_t raw_buffer, palette_t palette, trans_t trans, bool optimize)
{
    _index = true;
    if (optimize)
    {
        PaletteOptimizer optimizer(_width, _height);
        optimizer.process8bit(raw_buffer, palette, trans);
        _raw_buffer = optimizer.buffer();
        _palette = optimizer.palette();
        _trans = optimizer.trans();
        _palette_size = optimizer.palette_size();
        _trans_size = optimizer.trans_size();
    }
    else
    {
        _raw_buffer = raw_buffer;
        _palette = palette;
        _trans = trans;
        _palette_size = 255;
        _trans_size = 255;
    }
    _image_rows.reset(new unsigned char*[_height]);
    for (size_t i = 0; i < _height; ++i)
    {
        _image_rows[i] = _raw_buffer.get() + i * _width;
    }
    _process();
}

void PNGWriter::_process()
{
    if (_optimize)
    {
        int rc;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
        MultithreadTask task(this, _verbose);
        pthread_t threads[8];
        for (size_t i = 0; i < 8; ++i)
        {
            rc = pthread_create(&threads[i], &attr, MultithreadTask::thread_main, reinterpret_cast<void*>(&task));
            if (rc)
            {
                std::cout << "pthread create error" << std::endl;
            }
        }
        for (size_t i = 0; i < 8; ++i)
        {
            void* status;
            rc = pthread_join(threads[i], &status);
            if (rc)
            {
                std::cout << "pthread join error" << std::endl;
            }
        }
        int best_index = task.best_index();
        if (best_index > -1)
        {
            if (_verbose)
            {
                std::cout << "best result: ";
                parameters[best_index].print(task.best_size());
            }
            unsigned char* content = _file_content.get();
            task.flush(content, _file_size);
            _file_content.reset(content);
            _valid = true;
        }
    }
    else
    {
        Buffer* buffer = new Buffer();
        compress(6, buffer);
        unsigned char* content = _file_content.get();
        buffer->flush(content, _file_size);
        _file_content.reset(content);
        delete buffer;
        _valid = true;
    }
}

void PNGWriter::write(const char* filepath)
{
    if (_valid)
    {
        FILE * fp = fopen(filepath, "wb");
        fwrite(_file_content.get(), 1 , _file_size , fp);
        fclose(fp);
    }
}

void PNGWriter::compress(size_t parameter_index, Buffer* buffer)
{
    png_structp png = 0;
    png_infop info = 0;
    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
    if (!png)
    {
        return;
    }
    info = png_create_info_struct(png);
    if (!info)
    {
        return;
    }

    png_set_write_fn(png, reinterpret_cast<void*>(buffer), buffer_write, dummy_flash);

    parameter* param = parameters + parameter_index;
    if (param->get_type() == PNG_WRITER_USE_ZLIB)
    {
        png_set_filter(png, PNG_FILTER_TYPE_BASE, param->get_filter());
        png_set_compressor_type(png, PNG_WRITER_USE_ZLIB);
        png_set_compression_strategy(png, param->get_strategy());
        png_set_compression_window_bits(png, param->get_window_bits());
        png_set_compression_level(png, Z_BEST_COMPRESSION);
        png_set_compression_mem_level(png, MAX_MEM_LEVEL);
    }
    else // PNG_WRITER_USE_ZOPFLI
    {
        png_set_filter(png, PNG_FILTER_TYPE_BASE, param->get_filter());
        png_set_compressor_type(png, PNG_WRITER_USE_ZOPFLI);
        png_set_compression_level(png, 15);
    }
    bool packing = false;
    if (_index)
    {
        size_t bitlength = 8;
        if (_palette_size <= 2)
        {
            bitlength = 1;
            packing = true;
        }
        else if (_palette_size <= 4)
        {
            bitlength = 2;
            packing = true;
        }
        else if (_palette_size <= 16)
        {
            bitlength = 4;
            packing = true;
        }
        png_set_IHDR(png, info, _width, _height, bitlength, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
        png_set_PLTE(png, info, _palette.get(), _palette_size);
        if (_trans_size > 0)
        {
            png_set_tRNS(png, info, _trans.get(), _trans_size, NULL);
        }
    }
    else if (_has_alpha)
    {
        png_set_IHDR(png, info, _width, _height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    }
    else
    {
        png_set_IHDR(png, info, _width, _height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
            PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
    }
    png_write_info(png, info);
    if (packing)
    {
        png_set_packing(png);
    }
    png_write_image(png, _image_rows.get());
    png_write_end(png, info);
};
<|endoftext|>


<commit_before>#include "RadixSort.h"
#include <random>

RadixSort::RadixSort (GLuint _numblocks)
	: blocksize (512), numblocks (_numblocks)
{
	// load shaders
	counting.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/counting.glsl", "shaders/simulation/include.glsl");
	counting.Link ();
	blockscan.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/blockscan.glsl", "shaders/simulation/include.glsl");
	blockscan.Link ();
	globalsort.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/globalsort.glsl", "shaders/simulation/include.glsl");
	globalsort.Link ();
	addblocksum.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/addblocksum.glsl", "shaders/simulation/include.glsl");
	addblocksum.Link ();

	// create buffer objects
	glGenBuffers (3, buffers);

	// allocate input buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, buffer);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (particleinfo_t) * blocksize * numblocks, NULL, GL_DYNAMIC_DRAW);

	// allocate prefix sum buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, prefixsums);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * blocksize * numblocks, NULL, GL_DYNAMIC_DRAW);

	// create block sum buffers
	uint32_t numblocksums = 4 * numblocks;
	{
		int n = ceil (log (((numblocksums + blocksize - 1) / blocksize) * blocksize) / log (blocksize));
		n++;
		blocksums.resize (n);
		glGenBuffers (n, &blocksums[0]);
	}
	for (int i = 0; i < blocksums.size (); i++)
	{
		GLuint &blocksum = blocksums[i];
		// allocate a single block sum buffer
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		numblocksums = ((numblocksums + blocksize - 1) / blocksize) * blocksize;
		if (numblocksums < 1)
			numblocksums = 1;
		glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * numblocksums, NULL, GL_STATIC_DRAW);
		numblocksums /= blocksize;
	}

	// allocate output buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, result);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (particleinfo_t) * blocksize * numblocks, NULL, GL_STATIC_DRAW);

	// pass block sum offsets to the shader programs
	glm::uvec4 blocksumoffsets (0, numblocks, numblocks * 2, numblocks * 3);
	glProgramUniform4uiv (counting.get (), counting.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));
	glProgramUniform4uiv (globalsort.get (), globalsort.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));

	// query uniform locations
	counting_bitshift = counting.GetUniformLocation ("bitshift");
	globalsort_bitshift = globalsort.GetUniformLocation ("bitshift");

	// clear block sum buffers
	for (int blocksum : blocksums)
	{
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		glClearBufferData (GL_SHADER_STORAGE_BUFFER, GL_RGBA32UI, GL_RGBA, GL_UNSIGNED_INT, NULL);
	}
	glMemoryBarrier (GL_BUFFER_UPDATE_BARRIER_BIT);
}

RadixSort::~RadixSort (void)
{
	// cleanup
	glDeleteBuffers (blocksums.size (), &blocksums[0]);
	glDeleteBuffers (3, buffers);
}

GLuint RadixSort::GetBuffer (void) const
{
	// return the current input buffer
	return buffer;
}

void RadixSort::Run (unsigned int numbits)
{
	// sort bits from least to most significant
	for (int i = 0; i < (numbits + 1) >> 1; i++)
	{
		SortBits (2 * i);
		// swap the buffer objects
		std::swap (result, buffer);
	}
}

/** Integer power.
 * Calculates an integer power.
 * \param x base
 * \param y exponent
 * \returns x to the power of y
 */
uint32_t intpow (uint32_t x, uint32_t y)
{
	uint32_t r = 1;
	while (y)
	{
		if (y & 1)
			r *= x;
		y >>= 1;
		x *= x;
	}
	return r;
}

void RadixSort::SortBits (int bits)
{
	// pass current bit shift to the shader programs
	glProgramUniform1i (counting.get (), counting_bitshift, bits);
	glProgramUniform1i (globalsort.get (), globalsort_bitshift, bits);

	// set buffer bindings
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 2, blocksums.front ());
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 3, result);

	// counting
	counting.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);

	// create block sums level by level
	blockscan.Use ();
	uint32_t numblocksums = (4 * numblocks) / blocksize;
	for (int i = 0; i < blocksums.size () - 1; i++)
	{
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		numblocksums /= blocksize;
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// add block sums level by level (in reversed order)
	addblocksum.Use ();
	for (int i = blocksums.size () - 3; i >= 0; i--)
	{
		uint32_t numblocksums = (4 * numblocks) / intpow (blocksize, i + 1);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// map values to their global position in the output buffer
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	globalsort.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
}
<commit_msg>Remove C++11 dependency.<commit_after>#include "RadixSort.h"
#include <random>

RadixSort::RadixSort (GLuint _numblocks)
	: blocksize (512), numblocks (_numblocks)
{
	// load shaders
	counting.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/counting.glsl", "shaders/simulation/include.glsl");
	counting.Link ();
	blockscan.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/blockscan.glsl", "shaders/simulation/include.glsl");
	blockscan.Link ();
	globalsort.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/globalsort.glsl", "shaders/simulation/include.glsl");
	globalsort.Link ();
	addblocksum.CompileShader (GL_COMPUTE_SHADER, "shaders/radixsort/addblocksum.glsl", "shaders/simulation/include.glsl");
	addblocksum.Link ();

	// create buffer objects
	glGenBuffers (3, buffers);

	// allocate input buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, buffer);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (particleinfo_t) * blocksize * numblocks, NULL, GL_DYNAMIC_DRAW);

	// allocate prefix sum buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, prefixsums);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * blocksize * numblocks, NULL, GL_DYNAMIC_DRAW);

	// create block sum buffers
	uint32_t numblocksums = 4 * numblocks;
	{
		int n = ceil (log (((numblocksums + blocksize - 1) / blocksize) * blocksize) / log (blocksize));
		n++;
		blocksums.resize (n);
		glGenBuffers (n, &blocksums[0]);
	}
	for (int i = 0; i < blocksums.size (); i++)
	{
		GLuint &blocksum = blocksums[i];
		// allocate a single block sum buffer
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		numblocksums = ((numblocksums + blocksize - 1) / blocksize) * blocksize;
		if (numblocksums < 1)
			numblocksums = 1;
		glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (uint32_t) * numblocksums, NULL, GL_STATIC_DRAW);
		numblocksums /= blocksize;
	}

	// allocate output buffer
	glBindBuffer (GL_SHADER_STORAGE_BUFFER, result);
	glBufferData (GL_SHADER_STORAGE_BUFFER, sizeof (particleinfo_t) * blocksize * numblocks, NULL, GL_STATIC_DRAW);

	// pass block sum offsets to the shader programs
	glm::uvec4 blocksumoffsets (0, numblocks, numblocks * 2, numblocks * 3);
	glProgramUniform4uiv (counting.get (), counting.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));
	glProgramUniform4uiv (globalsort.get (), globalsort.GetUniformLocation ("blocksumoffsets"), 1,
			glm::value_ptr (blocksumoffsets));

	// query uniform locations
	counting_bitshift = counting.GetUniformLocation ("bitshift");
	globalsort_bitshift = globalsort.GetUniformLocation ("bitshift");

	// clear block sum buffers
	for (int i = 0; i < blocksums.size (); i++)
	{
		int &blocksum = blocksums[i];
		glBindBuffer (GL_SHADER_STORAGE_BUFFER, blocksum);
		glClearBufferData (GL_SHADER_STORAGE_BUFFER, GL_RGBA32UI, GL_RGBA, GL_UNSIGNED_INT, NULL);
	}
	glMemoryBarrier (GL_BUFFER_UPDATE_BARRIER_BIT);
}

RadixSort::~RadixSort (void)
{
	// cleanup
	glDeleteBuffers (blocksums.size (), &blocksums[0]);
	glDeleteBuffers (3, buffers);
}

GLuint RadixSort::GetBuffer (void) const
{
	// return the current input buffer
	return buffer;
}

void RadixSort::Run (unsigned int numbits)
{
	// sort bits from least to most significant
	for (int i = 0; i < (numbits + 1) >> 1; i++)
	{
		SortBits (2 * i);
		// swap the buffer objects
		std::swap (result, buffer);
	}
}

/** Integer power.
 * Calculates an integer power.
 * \param x base
 * \param y exponent
 * \returns x to the power of y
 */
uint32_t intpow (uint32_t x, uint32_t y)
{
	uint32_t r = 1;
	while (y)
	{
		if (y & 1)
			r *= x;
		y >>= 1;
		x *= x;
	}
	return r;
}

void RadixSort::SortBits (int bits)
{
	// pass current bit shift to the shader programs
	glProgramUniform1i (counting.get (), counting_bitshift, bits);
	glProgramUniform1i (globalsort.get (), globalsort_bitshift, bits);

	// set buffer bindings
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 2, blocksums.front ());
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 3, result);

	// counting
	counting.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);

	// create block sums level by level
	blockscan.Use ();
	uint32_t numblocksums = (4 * numblocks) / blocksize;
	for (int i = 0; i < blocksums.size () - 1; i++)
	{
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		numblocksums /= blocksize;
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// add block sums level by level (in reversed order)
	addblocksum.Use ();
	for (int i = blocksums.size () - 3; i >= 0; i--)
	{
		uint32_t numblocksums = (4 * numblocks) / intpow (blocksize, i + 1);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, blocksums[i]);
		glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, blocksums[i + 1]);
		glDispatchCompute (numblocksums > 0 ? numblocksums : 1, 1, 1);
		glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
	}

	// map values to their global position in the output buffer
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 0, buffer);
	glBindBufferBase (GL_SHADER_STORAGE_BUFFER, 1, prefixsums);
	globalsort.Use ();
	glDispatchCompute (numblocks, 1, 1);
	glMemoryBarrier (GL_SHADER_STORAGE_BARRIER_BIT);
}
<|endoftext|>


<commit_before>#include "RayTracer.hpp"
#include "Tree.hpp"
#include <ctime>
#include <math.h>

//temporary variables
Vec3Df testRayOrigin;
Vec3Df testRayDestination;
string mesh;
extern unsigned int textures[2];
extern Tree MyTree;
int alternateX, alternateY;

//use this function for any preprocessing of the mesh.
int init(int argc, char **argv){
    // skip program name argv[0] if present
    argc -= (argc > 0);
    argv += (argc > 0);

    option::Stats stats(usage, argc, argv);
    option::Option* options = (option::Option*)calloc(stats.options_max,
            sizeof(option::Option));
    option::Option* buffer = (option::Option*)calloc(stats.buffer_max,
            sizeof(option::Option));

    option::Parser parse(usage, argc, argv, options, buffer);

    if(parse.error())
        return 1;

    if(options[HELP]){
        int columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
        option::printUsage(fwrite, stdout, usage, columns);
        return 2;
    }

	mesh = "0";
    if(options[MESH]){
        const char* arg = options[MESH].last()->arg;
        if(arg != 0){
            mesh = arg;
        }
    }

	if (options[RAYTRACEX]){
		const char* arg = options[RAYTRACEX].last()->arg;
		if (arg != 0){
			alternateX = stoi(arg);
		}
	}

	if(options[RAYTRACEY]){
		const char* arg = options[RAYTRACEY].last()->arg;
		if (arg != 0){
			alternateY = stoi(arg);
		}
	}

    if(mesh == "0")
        mesh = "cube";
    else if(mesh == "1")
        mesh = "simple_monkey";
    else if(mesh == "2")
        mesh = "monkey";
    else if(mesh == "3")
        mesh = "dodgeColorTest";

    mesh = string("mesh/").append(mesh).append(".obj");
    MyMesh.loadMesh(mesh.c_str(), true);
    MyMesh.computeVertexNormals();
    MyTree.build(MyMesh);

    //one first move: initialize the first light source
    //at least ONE light source has to be in the scene!!!
    //here, we set it to the current location of the camera
    MyLightPositions.push_back(MyCameraPosition);

    if(options[RAYTRACE]){
        startRayTracing(activeTexIndex, true);
        return 255;
    }

    return 0;
}

//transformer le x, y en position 3D
void produceRay(int x_I, int y_I, Vec3Df * origin, Vec3Df * dest){
    int viewport[4];
    double modelview[16];
    double projection[16];
    //point sur near plane
    //double positionN[3];
    //point sur far plane
    //double positionF[3];
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //recuperer matrices
    glGetDoublev(GL_PROJECTION_MATRIX, projection); //recuperer matrices
    glGetIntegerv(GL_VIEWPORT, viewport); //viewport
    int y_new = viewport[3] - y_I;

    double x, y, z;

    gluUnProject(x_I, y_new, 0, modelview, projection, viewport, &x, &y, &z);
    origin->p[0] = float(x);
    origin->p[1] = float(y);
    origin->p[2] = float(z);
    gluUnProject(x_I, y_new, 1, modelview, projection, viewport, &x, &y, &z);
    dest->p[0] = float(x);
    dest->p[1] = float(y);
    dest->p[2] = float(z);
}

void produceRay(int x_I, int y_I, Vec3Df & origin, Vec3Df & dest){
    produceRay(x_I, y_I, &origin, &dest);
}

Vec3Df origin00, dest00;
Vec3Df origin01, dest01;
Vec3Df origin10, dest10;
Vec3Df origin11, dest11;

void raytracePart(Image* result, int w, int h, int xx, int yy, int ww, int hh){
    Vec3Df origin, dest;
    for(float y = yy;y < hh;y++){
        for(float x = xx;x < ww;x++){
            //svp, decidez vous memes quels parametres vous allez passer à la fonction
            //c'est le stront a la plafond, c'est drôle
            //e.g., maillage, triangles, sphères etc.
            Vec3Df total(0, 0, 0);
            for(unsigned int xs = 0;xs < MSAA;xs++){
                for(unsigned int ys = 0;ys < MSAA;ys++){
                    float xscale = 1.0f - (x + float(xs) / MSAA) / (w - 1);
                    float yscale = float(y + float(ys) / MSAA) / (h - 1);
#ifdef LINUX
                    yscale = 1.0f - yscale;
#endif
                    origin = yscale
                            * (xscale * origin00 + (1 - xscale) * origin10)
                            + (1 - yscale)
                                    * (xscale * origin01
                                            + (1 - xscale) * origin11);
                    dest = yscale * (xscale * dest00 + (1 - xscale) * dest10)
                            + (1 - yscale)
                                    * (xscale * dest01 + (1 - xscale) * dest11);

                    total += performRayTracing(origin, dest);
                }
            }

            // calculate average color
            total /= MSAA * MSAA;
            // result->_image
            result->_image[(y * result->_width + x) * 3 + 0] = total[0];
            result->_image[(y * result->_width + x) * 3 + 1] = total[1];
            result->_image[(y * result->_width + x) * 3 + 2] = total[2];
        }
    }
}

void startRayTracing(int texIndex, bool verbose){
    if(verbose)
        cout << "Raytracing" << endl;
    int w = verbose ? RAYTRACE_RES_X : PREVIEW_RES_X;
    int h = verbose ? RAYTRACE_RES_Y : PREVIEW_RES_Y;
	w = alternateX ? alternateX : w;
	h = alternateY ? alternateY : h;

    Image result(w, h);

    produceRay(0, 0, &origin00, &dest00);
    produceRay(0, WINDOW_RES_X - 1, &origin01, &dest01);
    produceRay(WINDOW_RES_X - 1, 0, &origin10, &dest10);
    produceRay(WINDOW_RES_X - 1, WINDOW_RES_Y - 1, &origin11, &dest11);

    // Perform timing
    time_t start, end, ticks;
    start = clock();

    // multithread
#if THREADS != 0
    std::thread** th = (std::thread**)alloca(THREADS * sizeof(std::thread*));
    int subw = w / THREADS;

    for(unsigned int i = 0;i < THREADS;i++)
    th[i] = new std::thread(raytracePart, &result, w, h, i * subw, 0,
            (i + 1) * subw, h);			// i * subw, 0, subw, h);

    // wait for them to finish
    for(unsigned int i = 0;i < THREADS;i++)
    th[i]->join();

    // kill them all
    for(unsigned int i = 0;i < THREADS;i++)
    delete th[i];
#else
    raytracePart(&result, w, h, 0, 0, w, h);
#endif

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    start = end;
    float millis = ticks * 1000. / CLOCKS_PER_SEC;

    if(verbose)
        printf("Rendering took %.0f ms cpu seconds and %.0f ms wall time\n",
                millis, millis / fmax(THREADS, 1));

    // write to texture
    glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT,
            &result._image[0]);

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Uploading to GPU took %.0f ms\n", millis);

    if(verbose)
        result.writeImage("result");
}

#define VEWY_HIGH 10e6f

Vec3Df black(0, 0, 0);

//return the color of your pixel.
Vec3Df performRayTracing(const Vec3Df & origin, const Vec3Df & dest){
    Ray ray = Ray(black, origin, dest);

    // calculate nearest triangle
    Triangle* triangle;
    float dist = MyTree.collide(ray, &triangle);

    Vec3Df light(17, 8, 20);
    Vec3Df lightColor(0.2f, 0.3f, 1.0f);

    Vec3Df impact = origin + ray.dir * dist;
    Vec3Df tolight = light - impact;
    Vec3Df tocam = origin - impact;
    tolight.normalize();

    // background
    if(!triangle){
        if(ray.dir.p[2] < 0){
			float height = origin.p[2];
            float a = -height / ray.dir.p[2];
            float x = origin.p[0] + a * ray.dir.p[0];
			float y = origin.p[1] + a * ray.dir.p[1];
			if (height < 0)
				return Vec3Df(0, 0.3f, 0);

            bool white = true;
			if (x > floor(x) + 0.5f) white = !white;
			if (y > floor(y) + 0.5f) white = !white;

            if(white)
                return Vec3Df(0.1f, 0.1f, 0.1f);
            else
                return Vec3Df(0.9f, 0.9f, 0.9f);
        }else
            return Vec3Df(0, 0.6, 0.99);
    }

    // ambient lighting
    Vec3Df color;
    color += Vec3Df(0.2f, 0.2f, 0.2f);

    // diffuse
    float angle = dot(triangle->normal, tolight) * 2;
    if(angle > 0)
        color += angle * lightColor;

    // specular
    float angle2 = dot(tocam, tolight) * 0.5f;
    if(angle2 > 0)
        color += angle2 * lightColor;

    // reflection
    Vec3Df r = ray.dir - 2*dot(ray.dir, triangle->normal)*triangle->normal;
    Ray reflectedRay = Ray(ray.color, impact, impact + r);

    // refraction
    float inIndex = 1;
    float outIndex = 1;
    float inDivOut = inIndex/outIndex;
    float cosIncident = dot(ray.dir, triangle->normal);
    float temp = inDivOut*inDivOut * 1-cosIncident*cosIncident;
    if(temp <= 1) {
    	float temp2 = inDivOut *  cosIncident - sqrt(1-temp);
    	Vec3Df t =inDivOut * ray.dir + Vec3Df(temp2, temp2, temp);
    	Ray transmittedRay = Ray(ray.color, impact, impact + t);
    } //temp > 1 means no refraction, only (total) reflection.

    // return color
    return color;
}

void drawCube(AABB* cube) {
	if (cube->sub) {
		//glColor3f(1, 0.5, 0.5);
		for (int i = 0; i < 8; i++)
			drawCube(cube->sub[i]);
	}
	if (!cube->leaves.empty()) {
		//glColor3f(0, 0.5, 0.5);
		float dim = cube->radius * 2;
		for (int axis = 0; axis < 3; axis++) {
			for (int x = 0; x < 2; x++) {
				for (int y = 0; y < 2; y++) {
					Vec3Df v = cube->pos;
					v.p[(axis + 1) % 3] += x * dim;
					v.p[(axis + 2) % 3] += y * dim;

					glVertex3f(v.p[0], v.p[1], v.p[2]);
					glVertex3f(
						v.p[0] + ((axis == 0) ? dim : 0),
						v.p[1] + ((axis == 1) ? dim : 0),
						v.p[2] + ((axis == 2) ? dim : 0)
						);
				}
			}
		}
	}
}

void yourDebugDraw(){
	glColor3f(1, 0.5, 0.5);
	glLineWidth(10);
	glBegin(GL_LINES);
	drawCube(MyTree.root);
	glEnd();
}

void yourKeyboardFunc(char t, int x, int y){
    // do what you want with the keyboard input t.
    // x, y are the screen position

    //here I use it to get the coordinates of a ray, which I then draw in the debug function.
    produceRay(x, y, testRayOrigin, testRayDestination);

    std::cout << t << " pressed! The mouse was in location " << x << "," << y
            << "!" << std::endl;
}
<commit_msg>Actually fixed refraction calculation now.<commit_after>#include "RayTracer.hpp"
#include "Tree.hpp"
#include <ctime>
#include <math.h>

//temporary variables
Vec3Df testRayOrigin;
Vec3Df testRayDestination;
string mesh;
extern unsigned int textures[2];
extern Tree MyTree;
int alternateX, alternateY;

//use this function for any preprocessing of the mesh.
int init(int argc, char **argv){
    // skip program name argv[0] if present
    argc -= (argc > 0);
    argv += (argc > 0);

    option::Stats stats(usage, argc, argv);
    option::Option* options = (option::Option*)calloc(stats.options_max,
            sizeof(option::Option));
    option::Option* buffer = (option::Option*)calloc(stats.buffer_max,
            sizeof(option::Option));

    option::Parser parse(usage, argc, argv, options, buffer);

    if(parse.error())
        return 1;

    if(options[HELP]){
        int columns = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
        option::printUsage(fwrite, stdout, usage, columns);
        return 2;
    }

	mesh = "0";
    if(options[MESH]){
        const char* arg = options[MESH].last()->arg;
        if(arg != 0){
            mesh = arg;
        }
    }

	if (options[RAYTRACEX]){
		const char* arg = options[RAYTRACEX].last()->arg;
		if (arg != 0){
			alternateX = stoi(arg);
		}
	}

	if(options[RAYTRACEY]){
		const char* arg = options[RAYTRACEY].last()->arg;
		if (arg != 0){
			alternateY = stoi(arg);
		}
	}

    if(mesh == "0")
        mesh = "cube";
    else if(mesh == "1")
        mesh = "simple_monkey";
    else if(mesh == "2")
        mesh = "monkey";
    else if(mesh == "3")
        mesh = "dodgeColorTest";

    mesh = string("mesh/").append(mesh).append(".obj");
    MyMesh.loadMesh(mesh.c_str(), true);
    MyMesh.computeVertexNormals();
    MyTree.build(MyMesh);

    //one first move: initialize the first light source
    //at least ONE light source has to be in the scene!!!
    //here, we set it to the current location of the camera
    MyLightPositions.push_back(MyCameraPosition);

    if(options[RAYTRACE]){
        startRayTracing(activeTexIndex, true);
        return 255;
    }

    return 0;
}

//transformer le x, y en position 3D
void produceRay(int x_I, int y_I, Vec3Df * origin, Vec3Df * dest){
    int viewport[4];
    double modelview[16];
    double projection[16];
    //point sur near plane
    //double positionN[3];
    //point sur far plane
    //double positionF[3];
    glGetDoublev(GL_MODELVIEW_MATRIX, modelview); //recuperer matrices
    glGetDoublev(GL_PROJECTION_MATRIX, projection); //recuperer matrices
    glGetIntegerv(GL_VIEWPORT, viewport); //viewport
    int y_new = viewport[3] - y_I;

    double x, y, z;

    gluUnProject(x_I, y_new, 0, modelview, projection, viewport, &x, &y, &z);
    origin->p[0] = float(x);
    origin->p[1] = float(y);
    origin->p[2] = float(z);
    gluUnProject(x_I, y_new, 1, modelview, projection, viewport, &x, &y, &z);
    dest->p[0] = float(x);
    dest->p[1] = float(y);
    dest->p[2] = float(z);
}

void produceRay(int x_I, int y_I, Vec3Df & origin, Vec3Df & dest){
    produceRay(x_I, y_I, &origin, &dest);
}

Vec3Df origin00, dest00;
Vec3Df origin01, dest01;
Vec3Df origin10, dest10;
Vec3Df origin11, dest11;

void raytracePart(Image* result, int w, int h, int xx, int yy, int ww, int hh){
    Vec3Df origin, dest;
    for(float y = yy;y < hh;y++){
        for(float x = xx;x < ww;x++){
            //svp, decidez vous memes quels parametres vous allez passer à la fonction
            //c'est le stront a la plafond, c'est drôle
            //e.g., maillage, triangles, sphères etc.
            Vec3Df total(0, 0, 0);
            for(unsigned int xs = 0;xs < MSAA;xs++){
                for(unsigned int ys = 0;ys < MSAA;ys++){
                    float xscale = 1.0f - (x + float(xs) / MSAA) / (w - 1);
                    float yscale = float(y + float(ys) / MSAA) / (h - 1);
#ifdef LINUX
                    yscale = 1.0f - yscale;
#endif
                    origin = yscale
                            * (xscale * origin00 + (1 - xscale) * origin10)
                            + (1 - yscale)
                                    * (xscale * origin01
                                            + (1 - xscale) * origin11);
                    dest = yscale * (xscale * dest00 + (1 - xscale) * dest10)
                            + (1 - yscale)
                                    * (xscale * dest01 + (1 - xscale) * dest11);

                    total += performRayTracing(origin, dest);
                }
            }

            // calculate average color
            total /= MSAA * MSAA;
            // result->_image
            result->_image[(y * result->_width + x) * 3 + 0] = total[0];
            result->_image[(y * result->_width + x) * 3 + 1] = total[1];
            result->_image[(y * result->_width + x) * 3 + 2] = total[2];
        }
    }
}

void startRayTracing(int texIndex, bool verbose){
    if(verbose)
        cout << "Raytracing" << endl;
    int w = verbose ? RAYTRACE_RES_X : PREVIEW_RES_X;
    int h = verbose ? RAYTRACE_RES_Y : PREVIEW_RES_Y;
	w = alternateX ? alternateX : w;
	h = alternateY ? alternateY : h;

    Image result(w, h);

    produceRay(0, 0, &origin00, &dest00);
    produceRay(0, WINDOW_RES_X - 1, &origin01, &dest01);
    produceRay(WINDOW_RES_X - 1, 0, &origin10, &dest10);
    produceRay(WINDOW_RES_X - 1, WINDOW_RES_Y - 1, &origin11, &dest11);

    // Perform timing
    time_t start, end, ticks;
    start = clock();

    // multithread
#if THREADS != 0
    std::thread** th = (std::thread**)alloca(THREADS * sizeof(std::thread*));
    int subw = w / THREADS;

    for(unsigned int i = 0;i < THREADS;i++)
    th[i] = new std::thread(raytracePart, &result, w, h, i * subw, 0,
            (i + 1) * subw, h);			// i * subw, 0, subw, h);

    // wait for them to finish
    for(unsigned int i = 0;i < THREADS;i++)
    th[i]->join();

    // kill them all
    for(unsigned int i = 0;i < THREADS;i++)
    delete th[i];
#else
    raytracePart(&result, w, h, 0, 0, w, h);
#endif

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    start = end;
    float millis = ticks * 1000. / CLOCKS_PER_SEC;

    if(verbose)
        printf("Rendering took %.0f ms cpu seconds and %.0f ms wall time\n",
                millis, millis / fmax(THREADS, 1));

    // write to texture
    glBindTexture(GL_TEXTURE_2D, textures[texIndex]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_FLOAT,
            &result._image[0]);

    // calculate elapsed time
    end = clock();
    ticks = end - start;
    millis = ticks * 1000 / CLOCKS_PER_SEC;

    if(verbose)
        printf("Uploading to GPU took %.0f ms\n", millis);

    if(verbose)
        result.writeImage("result");
}

#define VEWY_HIGH 10e6f

Vec3Df black(0, 0, 0);

//return the color of your pixel.
Vec3Df performRayTracing(const Vec3Df & origin, const Vec3Df & dest){
    Ray ray = Ray(black, origin, dest);

    // calculate nearest triangle
    Triangle* triangle;
    float dist = MyTree.collide(ray, &triangle);

    Vec3Df light(17, 8, 20);
    Vec3Df lightColor(0.2f, 0.3f, 1.0f);

    Vec3Df impact = origin + ray.dir * dist;
    Vec3Df tolight = light - impact;
    Vec3Df tocam = origin - impact;
    tolight.normalize();

    // background
    if(!triangle){
        if(ray.dir.p[2] < 0){
			float height = origin.p[2];
            float a = -height / ray.dir.p[2];
            float x = origin.p[0] + a * ray.dir.p[0];
			float y = origin.p[1] + a * ray.dir.p[1];
			if (height < 0)
				return Vec3Df(0, 0.3f, 0);

            bool white = true;
			if (x > floor(x) + 0.5f) white = !white;
			if (y > floor(y) + 0.5f) white = !white;

            if(white)
                return Vec3Df(0.1f, 0.1f, 0.1f);
            else
                return Vec3Df(0.9f, 0.9f, 0.9f);
        }else
            return Vec3Df(0, 0.6, 0.99);
    }

    // ambient lighting
    Vec3Df color;
    color += Vec3Df(0.2f, 0.2f, 0.2f);

    // diffuse
    float angle = dot(triangle->normal, tolight) * 2;
    if(angle > 0)
        color += angle * lightColor;

    // specular
    float angle2 = dot(tocam, tolight) * 0.5f;
    if(angle2 > 0)
        color += angle2 * lightColor;

    // reflection
    Vec3Df r = ray.dir - 2*dot(ray.dir, triangle->normal)*triangle->normal;
    Ray reflectedRay = Ray(ray.color, impact, impact + r);

    // refraction
    float inIndex = 1;
    float outIndex = 1;
    float inDivOut = inIndex/outIndex;
    float cosIncident = dot(ray.dir, triangle->normal);
    float temp = inDivOut*inDivOut * 1-cosIncident*cosIncident;
    if(temp <= 1) {
    	Vec3Df t =inDivOut * ray.dir + (inDivOut *  cosIncident - sqrt(1-temp))*triangle->normal;
    	Ray transmittedRay = Ray(ray.color, impact, impact + t);
    } //temp > 1 means no refraction, only (total) reflection.

    // return color
    return color;
}

void drawCube(AABB* cube) {
	if (cube->sub) {
		//glColor3f(1, 0.5, 0.5);
		for (int i = 0; i < 8; i++)
			drawCube(cube->sub[i]);
	}
	if (!cube->leaves.empty()) {
		//glColor3f(0, 0.5, 0.5);
		float dim = cube->radius * 2;
		for (int axis = 0; axis < 3; axis++) {
			for (int x = 0; x < 2; x++) {
				for (int y = 0; y < 2; y++) {
					Vec3Df v = cube->pos;
					v.p[(axis + 1) % 3] += x * dim;
					v.p[(axis + 2) % 3] += y * dim;

					glVertex3f(v.p[0], v.p[1], v.p[2]);
					glVertex3f(
						v.p[0] + ((axis == 0) ? dim : 0),
						v.p[1] + ((axis == 1) ? dim : 0),
						v.p[2] + ((axis == 2) ? dim : 0)
						);
				}
			}
		}
	}
}

void yourDebugDraw(){
	glColor3f(1, 0.5, 0.5);
	glLineWidth(10);
	glBegin(GL_LINES);
	drawCube(MyTree.root);
	glEnd();
}

void yourKeyboardFunc(char t, int x, int y){
    // do what you want with the keyboard input t.
    // x, y are the screen position

    //here I use it to get the coordinates of a ray, which I then draw in the debug function.
    produceRay(x, y, testRayOrigin, testRayDestination);

    std::cout << t << " pressed! The mouse was in location " << x << "," << y
            << "!" << std::endl;
}
<|endoftext|>