<filename>example/example.py
'''++

Copyright (C) 2019 PrimeDevelopers

All rights reserved.

This file has been generated by the Automatic Component Toolkit (ACT) version 1.4.0.

Abstract: This is an autogenerated Python application that demonstrates the
 usage of the Python bindings of Ray Marching Library

Interface version: 1.1.0

'''


import os
import sys
import math
import LibRayMarching
from PIL import Image
import math

def Progress(Percentage, ShouldAbort):
	print(("=" * math.ceil(Percentage)) + "> " + str(math.ceil(Percentage)) + "%", end="\r")
	sys.stdout.flush();

class RayMarching:

	def __init__(self, width, height, dx, dy):
		self.Wrapper = LibRayMarching.Wrapper("../build/libraymarching");
		major, minor, micro = self.Wrapper.GetLibraryVersion();
		print("LibRayMarching version: {:d}.{:d}.{:d}".format(major, minor, micro));

		self.Scene = self.Wrapper.CreateRayMarching();
		print("Set size")
		self.Scene.SetScreenSize(width, height);
		self.Scene.SetProgressCallback(LibRayMarching.ProgressCallback(Progress));
		self.Width = width;
		self.Height = height;

		print("Set viewport")
		self.Scene.SetViewport(
			LibRayMarching.Vector(X = 3 + 14 * dx, Y = -3 + 14 * dy, Z = 4),
			LibRayMarching.Vector(X = -dx, Y = -dy, Z = -0.2),
			LibRayMarching.Vector(X = 0, Y = 0, Z = 1), math.pi*20/180);

		print("Set properties");
		self.Scene.SetShaderProperties(LibRayMarching.ShaderProperties(
			Oversampling = 2, 
			MaxBouncing = 5,
			SoftShadow = 50,
			FastNormalCalculation = True));
		self.Scene.SetBackground(LibRayMarching.Vector(X = 0.05, Y = 0, Z = 0.2), 30, 40);

	def BuildScene(self):
		print ("Create light")
		self.Scene.AddLight(LibRayMarching.Vector(9, -20, 25), LibRayMarching.Vector(1, 1, 1));
		
		print ("Create sphere")
		Sphere = self.Wrapper.CreateSphere(1);
		Sphere.SetMaterial(LibRayMarching.Material(
			Red = 0.5, Green = 0.1, Blue = 0.3,
			Ambient = 0.3,
			Diffuse = 1,
			Specular = 1,
			SpecularAlpha = 15));
		Sphere.SetSinusDistortion(0.06, 0.6);
		Sphere.Translate(LibRayMarching.Vector(X = 0, Y = 0, Z = 2));
		self.Scene.AddPrimitive(Sphere);
		
		print ("Create box")
		Box = self.Wrapper.CreateBox(
			LibRayMarching.Vector(X = 0.5, Y = 0.5, Z = 0.5)
		);
		Box.SetMaterial(LibRayMarching.Material(
			Red = 0.5, Blue = 0.1, Green = 0.3,
			Ambient = 0.3,
			Diffuse = 1,
			Specular = 1,
			SpecularAlpha = 15));
		Box.Translate(LibRayMarching.Vector(X = 3, Y = -3, Z = 2));
		self.Scene.AddPrimitive(Box);

		print ("Create capsule")
		Capsule = self.Wrapper.CreateCapsule(
			0.5,
			LibRayMarching.Vector(X = -0.5, Y = -0.5, Z = -0.5),
			LibRayMarching.Vector(X = 0.5, Y = 0.5, Z = 0.5)
		);
		Capsule.SetMaterial(LibRayMarching.Material(
			Blue = 0.5, Green = 0.1, Red = 0.3,
			Ambient = 0.3,
			Diffuse = 1,
			Specular = 1,
			SpecularAlpha = 15));
		Capsule.Translate(LibRayMarching.Vector(X = 6, Y = 0, Z = 2));
		self.Scene.AddPrimitive(Capsule);

		print ("Create cylinder")
		Cylinder = self.Wrapper.CreateCylinder(1, 2);
		Cylinder.SetMaterial(LibRayMarching.Material(
			Green = 0.5, Red = 0.1, Blue = 0.3,
			Ambient = 0.3,
			Diffuse = 1,
			Specular = 1,
			SpecularAlpha = 15));
		Cylinder.Translate(LibRayMarching.Vector(X = 0, Y = -3, Z = 2));		
		self.Scene.AddPrimitive(Cylinder);

		print ("Create torus")
		Torus = self.Wrapper.CreateTorus(0.7, 0.3);
		Torus.SetMaterial(LibRayMarching.Material(
			Green = 1, Blue = 1, Red = 1,
			Ambient = 0.05,
			Diffuse = 0.1,
			Specular = 0.3,
			SpecularAlpha = 15,
			Reflection = 0.6));
		Torus.Rotate(LibRayMarching.Vector(X = 1, Y = 0, Z = 0), math.pi/2);
		Torus.Translate(LibRayMarching.Vector(X = 3, Y = 0, Z = 2));		
		self.Scene.AddPrimitive(Torus);

		print ("Create transparent sphere")
		Sphere = self.Wrapper.CreateSphere(1);
		Sphere.SetMaterial(LibRayMarching.Material(
			Blue = 0.5, Red = 0.1, Green = 0.3,
			Ambient = 0.1,
			Diffuse = 0.2,
			Specular = 0.4,
			SpecularAlpha = 15,
			TransparencY = 0.5,
			Refraction = 1.33));
		Sphere.Translate(LibRayMarching.Vector(X = 6, Y = -3, Z = 2));
		self.Scene.AddPrimitive(Sphere);
		
		print ("Create menger sponge")
		MengerSponge = self.Wrapper.CreateMengerSponge(3);
		MengerSponge.SetMaterial(LibRayMarching.Material(
			Green = 0.5, Blue = 0.1, Red = 0.3,
			Ambient = 0.3,
			Diffuse = 0.5,
			Specular = 0.4,
			SpecularAlpha = 15));
		MengerSponge.Translate(LibRayMarching.Vector(X = 0, Y = -6, Z = 2));
		self.Scene.AddPrimitive(MengerSponge);

		print ("Create julia quaternion fractal")
		QuaternionFractal = self.Wrapper.CreateQuaternionFractal(10);
		QuaternionFractal.SetQuaternion(0.2, -0.4, 0, -0.6);
		QuaternionFractal.SetMaterial(LibRayMarching.Material(
			Green = 0.5, Blue = 0.1, Red = 0.5,
			Ambient = 0.3,
			Diffuse = 0.5,
			Specular = 0.4,
			SpecularAlpha = 15));
		QuaternionFractal.Translate(LibRayMarching.Vector(X = 3, Y = -6, Z = 2));
		self.Scene.AddPrimitive(QuaternionFractal);
		
		GSphere = self.Wrapper.CreateSphere(1.25);
		GBox = self.Wrapper.CreateBox(
			LibRayMarching.Vector(X = 1, Y = 1, Z = 1)
		);
		GSphere2 = self.Wrapper.CreateSphere(1.1);
		GSphere2.Rotate(LibRayMarching.Vector(X = 1, Y = 0, Z = 0), math.pi/2);
		GroupRCube = self.Wrapper.CreatePrimitiveGroup(LibRayMarching.GroupAction.Intersect);
		GroupRCube.AddPrimitive(GSphere);
		GroupRCube.AddPrimitive(GBox);

		GroupM = self.Wrapper.CreatePrimitiveGroup(LibRayMarching.GroupAction.Subtract);
		GroupM.AddPrimitive(GroupRCube);
		GroupM.AddPrimitive(GSphere2);
		GroupM.Translate(LibRayMarching.Vector(X = 6, Y = -6, Z = 2));
		GroupM.SetMaterial(LibRayMarching.Material(
			Green = 0.5, Blue = 0.5, Red = 0.1,
			Ambient = 0.3,
			Diffuse = 0.5,
			Specular = 0.4,
			SpecularAlpha = 15));			
		self.Scene.AddPrimitive(GroupM);
		
		print ("Create pane")
		Plane = self.Wrapper.CreatePlane(
			LibRayMarching.Vector(X = 0, Y = 0, Z = 0),
			LibRayMarching.Vector(X = 0, Y = 0, Z = 1)
		);
		Plane.SetMaterial(LibRayMarching.Material(
			Red = 0.2, Green = 0.2, Blue = 0.2,
			Ambient = 0.3,
			Diffuse = 1,
			Specular = 1,
			SpecularAlpha = 15));
		self.Scene.AddPrimitive(Plane);

	def RenderPixel(self, x, y):
		print ("Render scene")
		Pixel = self.Scene.RenderPixel(x, y);
		print ("Pixelcolor is " + str(Pixel))


	def Render(self, file, show):
		print ("Render scene")
		self.Scene.RenderScene();
		print ("")

		print ("Get buffer")
		color_buffer = self.Scene.GetColorBuffer();
		print ("Buffer length " + str(len(color_buffer)))

		img = Image.new('RGB', (self.Width, self.Height))
		pixels = img.load()
		for i in range(img.size[0]):    # for every col:
			for j in range(img.size[1]):    # For every row
				color = color_buffer[i + j * img.size[0]];
				# print color;    		
				pixels[i,j] = ((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF) # set the colour accordingly
		img.save(file + '.png')
		if show:
			img.show()

def main():	
	#Radian = 2 * math.pi * 27 / 401;
	#RM = RayMarching(600, 400, math.sin(Radian), math.cos(Radian));
	#RM.BuildScene();
	#RM.RenderPixel(50, 50);
	#RM.Render('ray_marching', True);

	for i in range(0, 400):
		if not os.path.isfile('round/frame_'+str(i)+'.png'):
			Radian = 2 * math.pi * i / 400;
			RM = RayMarching(600, 400, math.sin(Radian), math.cos(Radian));
			RM.BuildScene();
			RM.RenderPixel(225, 172);
			RM.Render('round/frame_' + str(i), False);

if __name__ == "__main__":
	try:
		main()
	except Exception as e:
		print(e)
