#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>
#include <cmath>
#include <limits>
#include <algorithm>
using namespace std;
struct Vector {
float x,y,z;
};
inline float operator * (const Vector &v1, const Vector &v2) {
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
}
inline Vector operator * (float t, const Vector &v1) {
Vector v2 = {v1.x * t, v1.y * t, v1.z *t};
return v2;
}
struct point {
float x,y,z;
};
inline Vector operator - (const point &p1, const point &p2) {
Vector v3= {p1.x - p2.x, p1.y -p2.y, p1.z - p2.z};
return v3;
}
inline Vector operator - (const Vector &v1, const Vector &v2) {
Vector v3= {v1.x - v2.x, v1.y -v2.y, v1.z - v2.z};
return v3;
}
inline point operator + (const point &p1, const Vector &v1 ) {
point p2 = {p1.x + v1.x, p1.y + v1.y, p1.z + p1.z};
return p2;
}
struct Ray {
point origin;
Vector dir;
};
struct Sphere {
point pos;
float radius_squared;
float size;
int materialId;
};
struct light {
point pos;
float red;
float green;
float blue;
};
struct material {
float reflection;
float red;
float green;
float blue;
};
class Image {
public:
void insertData (int width, int height, int bpp);
int getSize () const { return m_size; };
int getBitsPerPixel () const { return m_bitsPerPixel; };
inline int getWidth () { return m_width; };
inline int getHeight () { return m_height; };
private:
int m_size;
int m_bitsPerPixel;
int m_bytesPerPixel;
int m_width;
int m_height;
};
void Image::insertData (int width, int height, int bpp) {
m_width = width;
//cout << "Width " << m_width << endl;
m_height = height;
//cout << "Height " << m_height << endl;
m_bitsPerPixel = bpp;
//cout << "bitsPerPixel " << m_bitsPerPixel << endl;
m_bytesPerPixel = bpp >> 3;
m_size = m_width*m_height*m_bytesPerPixel;
}
class Scene {
public:
inline int getSphereContainerSize () { return sphereContainer.size(); }
inline int getLightContainerSize () { return lightContainer.size(); }
inline Sphere& getSphereReference (int i) { return sphereContainer[i]; }
inline point& getSphereCenter (int currentSphere) { return sphereContainer[currentSphere].pos; };
inline int getSphereRadius (int currentSphere) { return sphereContainer[currentSphere].size; };
inline material& getMaterial (int currentSphere) { return materialContainer[getMaterialId(currentSphere)]; };
inline int getMaterialId (int currentSphere) {return sphereContainer[currentSphere].materialId; };
inline light& getLight (int j) { return lightContainer[j]; };
inline void addSphere (const Sphere &sphere) { sphereContainer.push_back (sphere); }
inline void addMaterial (const material &material) { materialContainer.push_back (material); }
inline void addLight (const light &light) { lightContainer.push_back (light); }
std::vector <material> materialContainer;
std::vector <Sphere> sphereContainer;
std::vector <light> lightContainer;
private:
};
class FileManager {
public:
FileManager ();
FileManager (const char * fileName);
bool isFileOpen ();
void closeFile (bool choice);
void openFile ();
protected:
ifstream fileReader;
ofstream fileWriter;
int getPtrPosition;
};
FileManager::FileManager () {
fileWriter.open ("z.tga",ios::binary);
}
FileManager::FileManager (const char * fileName) {
fileReader.open (fileName);
}
bool FileManager::isFileOpen () {
if (fileReader.is_open() || fileWriter.is_open()) {
return true;
}
else {
cout << "The file could not be loaded, please try running the program again" << endl;
return false;
}
}
void FileManager::closeFile (bool choice) {
if (choice==0)
fileReader.close ();
else
fileWriter.close ();
}
class TGAManager : public FileManager
{
public:
TGAManager ();
void readHeaderInformation();
bool checkFileRead ();
bool checkHeaderData();
bool extractImageFeatures();
int getWidth();
int getHeight();
int getBpp();
void readTgaData (char * memoryAdress, int imageSize);
void writePreLoadedTgaData (char * memoryAdress, int imageSize);
inline void writeTgaData ();
void writeHeaderData (Image &image);
private:
char TGAheader[12];
char TGAcompare[12];
char header[6];
char finalBits [26];
int height;
int width;
int bpp;
};
TGAManager::TGAManager() : FileManager () {
TGAheader[0] = 0;
TGAheader[1] = 0;
TGAheader[2] = 2;
TGAheader[3] = 0;
TGAheader[4] = 0;
TGAheader[5] = 0;
TGAheader[6] = 0;
TGAheader[7] = 0;
TGAheader[8] = 0;
TGAheader[9] = 0;
TGAheader[10] = 0;
TGAheader[11] = 0;
}
void TGAManager::readHeaderInformation() {
fileReader.read (TGAcompare,sizeof(TGAcompare));
fileReader.read (header,sizeof(header));
}
bool TGAManager::checkFileRead() {
if (fileReader.eof () == 1) {
cout << "The eof bit was set while trying to read the TGA file. Please try run the program again with a different TGA file: " << endl;
return false;
}
else if (fileReader.bad () == 1) {
cout << "Badbit set. A likely loss of integrity of the stream happened. Please try to run with another TGA file: " << endl;
return false;
}
else if ((fileReader.fail () == 1) && (fileReader.bad () == 0)) {
cout << "FailBit set. An error likely related to the internal logic of the operation happened. Please try to run the program again: " << endl;
return false;
}
else
return true;
}
bool TGAManager::checkHeaderData() {
for (unsigned int i=0; i<sizeof (TGAcompare); i++) {
if (TGAcompare[i] != TGAheader[i]) {
cout << "The header file is corrupted in the: " << i << " byte of the file or it is not a valid tga file. Please try running the program again" << endl;
return false;
}
}
return true;
}
bool TGAManager::extractImageFeatures() {
width = header[1] * 256 + header[0];
height = header[3] * 256 + header[2];
bpp = header[4];
if (width <= 0 || height <= 0 || (header[4] != 24 && header[4] != 32)) {
cout << "The data about the file width, height or bpp is incorrect. Please try to load a different tga file: " << endl;
return false;
}
return true;
}
int TGAManager::getWidth () {
return width;
}
int TGAManager::getHeight () {
return height;
}
int TGAManager::getBpp () {
return bpp;
}
void TGAManager::readTgaData (char * memoryAdress, int imageSize) {
fileReader.read (memoryAdress, imageSize );
}
void TGAManager::writePreLoadedTgaData (char * memoryAdress, int imageSize) {
fileWriter.write (TGAcompare,sizeof(TGAcompare));
fileWriter.write (header,sizeof(header));
fileWriter.write (memoryAdress,imageSize);
}
void TGAManager::writeHeaderData (Image &image) {
fileWriter.write (TGAheader,sizeof(TGAcompare));
int test = image.getBitsPerPixel();
//fileWriter.write ();
cout << test << endl;
}
class TextManager : public FileManager
{
public:
TextManager (const char * filename);
void scanFile(Image &image, Scene &scene);
void getImageData (Image &image);
void getMaterialData (Scene &scene);
void getLightData (Scene &scene);
void getSphereData (Scene &scene);
void getData (Scene &scene);
int getLineValue (int size);
void getLineValue2 (float (&lineNumbers) [6], Scene &scene, int &lineNumbersIndex);
private:
std::string line;
float fractionaryTenPowers [4];
};
TextManager::TextManager (const char * fileName) : FileManager (fileName) {
fractionaryTenPowers[0] = 0.1;
fractionaryTenPowers[1] = 0.01;
fractionaryTenPowers[2] = 0.001;
fractionaryTenPowers[3] = 0.0001;
}
void TextManager::scanFile (Image &image, Scene &scene) {
//cout << "TextManager::scanFile" << endl;
while (fileReader.good()) {
getline (fileReader,line);
if (line == "Image")
getImageData (image);
else if (line == "Material")
getMaterialData (scene);
else if (line == "Light")
getLightData (scene);
else if (line == "Sphere")
getSphereData (scene);
}
}
void TextManager::getImageData(Image &image) {
//cout << "TextManager::getImageData" << endl;
int size,count=0;
int imageData[3];
while (line != "") {
getline (fileReader,line);
size = line.size ();
imageData[count] = getLineValue (size);
count++;
}
//cout << "The values of 'imageData[0]' it is: " << imageData[0] << "The values of 'imageData[1]' it is: " << imageData[1] << "The values of 'imageData[2' it is: " << imageData[2] << endl;
image.insertData (imageData[0],imageData[1],imageData[2]);
//cout << "The values of 'image.getWidth()' it is: " << image.getWidth() << "The values of 'image.getHeight()' it is: " << image.getHeight() << "The values of 'image.getBitsPerPixel()' it is: " << image.getBitsPerPixel() << endl;
}
void TextManager::getMaterialData (Scene &scene) {
//cout << "MaterialData" << endl;
int lineNumbersIndex=0, getLineValue2Counter=0;
float lineNumbers [6];
while (line != "") {
getline (fileReader,line);
if (line[0] != ' ')
continue;
getLineValue2 (lineNumbers, scene, lineNumbersIndex);
getLineValue2Counter++;
if (getLineValue2Counter==2) {
material material;
getLineValue2Counter=0;
lineNumbersIndex=0;
material.red = lineNumbers[0];
material.green = lineNumbers[1];
material.blue = lineNumbers[2];
material.reflection = lineNumbers[3];
scene.addMaterial (material);
}
}
}
void TextManager::getLightData (Scene &scene) {
//cout << "LightData" << endl;
int lineNumbersIndex=0, getLineValue2Counter=0;
float lineNumbers [6];
while (line != "") {
getline (fileReader,line);
if (line[0] != ' ')
continue;
getLineValue2 (lineNumbers, scene, lineNumbersIndex);
getLineValue2Counter++;
if (getLineValue2Counter==2) {
light light;
getLineValue2Counter=0;
lineNumbersIndex=0;
light.pos.x = lineNumbers[0];
light.pos.y = lineNumbers[1];
light.pos.z = lineNumbers[2];
light.red = lineNumbers[3];
light.green = lineNumbers[4];
light.blue = lineNumbers[5];
scene.addLight (light);
}
}
}
void TextManager::getSphereData (Scene &scene) {
//cout << "SphereData" << endl;
int lineNumbersIndex=0, getLineValue2Counter=0;
float lineNumbers [6];
while (line != "") {
getline (fileReader,line);
if (line[0] != ' ')
continue;
getLineValue2 (lineNumbers, scene, lineNumbersIndex);
/*cout << "The value of getLineValue2Counter it is: " << getLineValue2Counter << endl;
cout << '\n' << endl;
cout << '\n' << endl;*/
getLineValue2Counter++;
if (getLineValue2Counter==4) {
Sphere sphere;
getLineValue2Counter=0;
lineNumbersIndex=0;
//cout << "LineNumbers[5]" << lineNumbers[5] << endl;
sphere.pos.x = lineNumbers[0];
sphere.pos.y = lineNumbers[1];
sphere.pos.z = lineNumbers[2];
sphere.radius_squared = lineNumbers[3];
sphere.size = lineNumbers[4];
sphere.materialId = lineNumbers[5];
scene.addSphere (sphere);
// cout << "Sphere.materialID" << sphere.materialId << endl;
}
}
}
int TextManager::getLineValue (int size) {
//cout << "TextManager::getLineValue" << endl;
int finalValue=0;
for (int i=0; i<size; i++) {
if (line[i] >= '0' && line[i] <= '9') {
finalValue = 10*finalValue + line[i] - '0';
//cout << finalValue << endl;
}
}
return finalValue;
}
void TextManager::getLineValue2 (float (&lineNumbers) [6], Scene &scene, int &lineNumbersIndex) {
//cout << "getLineValue2" << endl;
int i=0;
bool negativo = false;
while (line[i] != ';') {
float integerValue=0, floatValue=0;
while (line[i] != '.' && line[i] != ';') {
if (line[i] >= '0' && line[i] <= '9')
integerValue = 10*integerValue + line[i] - '0';
else if (line[i] == '-')
negativo = true;
i++;
}
if (negativo) {
integerValue *= -1;
negativo = false;
}
for (int y=0; line[i] != ';'; i++) {
if (line[i] == ',') {
i++;
break;
}
if (line[i] >= '0' && line[i] <= '9') {
floatValue += (line[i] - '0') *fractionaryTenPowers[y];
y++;
}
}
lineNumbers[lineNumbersIndex] = integerValue+floatValue;
//cout << "The 'lineNumbers[lineNumbersIndex]' value it is: " << lineNumbers[lineNumbersIndex] << " and the lineNumbersIndex it is: " << lineNumbersIndex << endl;
//cout << "The i value it is: " << i << endl;
lineNumbersIndex++;
}
//cout << '\n' << endl;
}
class RayTracer {
public:
bool hitSphere (const Ray &Ray, const Sphere &sphere, float &t, float x, float y);
void draw (Image &myScene, Scene &scene);
};
bool RayTracer::hitSphere(const Ray &r, const Sphere &s, float &t, float x, float y)
{
Vector dist = s.pos - r.origin;
float B = r.dir * dist;
float D = B*B - dist * dist + s.size * s.size;
if (D < 0.0f)
return false;
float t0 = B - sqrtf(D);
float t1 = B + sqrtf(D);
bool retvalue = false;
if ((t0 > 0.1f) && (t0 < t))
{
t = t0;
retvalue = true;
}
if ((t1 > 0.1f) && (t1 < t))
{
t = t1;
retvalue = true;
}
return retvalue;
}
void RayTracer::draw(Image &myScene, Scene &scene)
{
int counter=0;
int counter2=0;
int counter3=0;
int counter4=0;
int counter5=0;
int counter6=0;
int counter7=0;
int counter8=0;
int counter9=0;
ofstream imageFile("z.tga",ios_base::binary);
//if (!imageFile)
//return false;
//
imageFile.put(0).put(0);
imageFile.put(2);
imageFile.put(0).put(0);
imageFile.put(0).put(0);
imageFile.put(0);
imageFile.put(0).put(0);
imageFile.put(0).put(0);
imageFile.put((unsigned char)(myScene.getWidth() & 0x00FF)).put((unsigned char)((myScene.getWidth() & 0xFF00) / 256));
imageFile.put((unsigned char)(myScene.getHeight() & 0x00FF)).put((unsigned char)((myScene.getHeight() & 0xFF00) / 256));
imageFile.put(24);
imageFile.put(0);
for (int y=0; y<768; ++y) {
for (int x=0; x<1024; ++x) {
float red = 0, green = 0, blue = 0;
float coef = 1.0f;
int level = 0;
Ray viewRay = { {float(x), float(y), -1000.0f}, { 0.0f, 0.0f, 1.0f}};
do
{
float t = 2000.0f;
int currentSphere= -1;
for (unsigned int i = 0; i < scene.sphereContainer.size(); ++i)
{
if (hitSphere(viewRay, scene.sphereContainer[i], t,x,y))
{
counter ++;
currentSphere = i;
}
}
if (currentSphere == -1) {
counter3++;
break;
}
point intersection = viewRay.origin + t * viewRay.dir;
if (x==300 && y==300) {
cout << "t value it is: " << t << endl;
cout << " viewRay.dir.x value it is: " << viewRay.dir.x << " viewRay.dir.y value it is: " << viewRay.dir.y << " viewRay.dir.z value it is: " << viewRay.dir.z << endl;
cout << " viewRay.origin.x value it is: " << viewRay.origin.x << " viewRay.origin.x value it is: " << viewRay.origin.y << " viewRay.origin.z value it is: " << viewRay.origin.z << endl;
cout << viewRay.origin.x + t*viewRay.dir.x << ' ' << viewRay.origin.y + t*viewRay.dir.y << ' ' << viewRay.origin.z + t*viewRay.dir.z << endl;
cout << intersection.x << ' ' << intersection.y << ' ' << intersection.z << endl;
}
Vector n = intersection - scene.sphereContainer[currentSphere].pos;
float temp = n * n;
if (temp == 0.0f) {
counter4++;
break;
}
temp = 1.0f / sqrtf(temp);
n = temp * n;
material currentMat = scene.materialContainer[scene.sphereContainer[currentSphere].materialId];
//cout << "Light Container Size: " << scene.lightContainer.size() << endl;
for (unsigned int j = 0; j < scene.lightContainer.size(); ++j) {
counter7++;
light current = scene.lightContainer[j];
Vector dist = current.pos - intersection;
if (n * dist <= 0.0f) {
counter5++;
continue;
}
float t = sqrtf(dist*dist);
if ( t <= 0.0f ) {
counter6++;
continue;
}
counter9++;
Ray lightRay;
lightRay.origin = intersection;
lightRay.dir = (1/t) * dist;
bool inShadow = false;
for (unsigned int i = 0; i < scene.sphereContainer.size(); ++i) {
if (hitSphere(lightRay, scene.sphereContainer[i], t,x,y)) {
inShadow = true;
counter8++;
break;
}
}
if (!inShadow) {
counter2++;
float lambert = (lightRay.dir * n) * coef;
red += lambert * current.red * currentMat.red;
green += lambert * current.green * currentMat.green;
blue += lambert * current.blue * currentMat.blue;
}
}
coef *= currentMat.reflection;
float reflet = 2.0f * (viewRay.dir * n);
viewRay.origin = intersection;
viewRay.dir = viewRay.dir - reflet * n;
level++;
}
while ((coef > 0.0f) && (level < 10));
imageFile.put((unsigned char)min(blue*255.0f,255.0f)).put((unsigned char)min(green*255.0f, 255.0f)).put((unsigned char)min(red*255.0f, 255.0f));
}
}
cout << '\n' << endl;
cout << "Counter 1: " << counter << endl;
cout << "Counter 2: " << counter2 << endl;
cout << "Counter 3: " << counter3 << endl;
//cout << "Counter 4: " << counter4 << endl;
cout << "Counter 5: " << counter5 << endl;
//cout << "Counter 6: " << counter6 << endl;
cout << "Counter 7: " << counter7 << endl;
cout << "Counter 8: " << counter8 << endl;
cout << "Counter 9: " << counter9 << endl;
//return true;
}
int main (int argc, char* argv[]) {
Image myScene;
Scene scene;
{
TextManager textManager (argv[1]);
if (textManager.isFileOpen()) {
textManager.scanFile (myScene, scene);
textManager.closeFile(0);
}
}
TGAManager tgaManager;
if (tgaManager.isFileOpen()) {
RayTracer rayTracer;
rayTracer.draw (myScene, scene);
//tgaManager.closeFile(1);
}
return 0;
}