634 lines
16 KiB
C#
634 lines
16 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
public class MegaGrab : MonoBehaviour
|
|
{
|
|
public Camera SrcCamera;
|
|
|
|
public KeyCode GrabKey = KeyCode.S;
|
|
|
|
public int ResUpscale = 1;
|
|
|
|
public float Blur = 1f;
|
|
|
|
public int AASamples = 8;
|
|
|
|
public AnisotropicFiltering FilterMode = AnisotropicFiltering.ForceEnable;
|
|
|
|
public bool UseJitter;
|
|
|
|
public string SaveName = "Grab";
|
|
|
|
public string Format = "dddd MMM dd yyyy HH_mm_ss";
|
|
|
|
public string Enviro = string.Empty;
|
|
|
|
public string Path = string.Empty;
|
|
|
|
public bool UseDOF;
|
|
|
|
public float focalDistance = 8f;
|
|
|
|
public int totalSegments = 8;
|
|
|
|
public float sampleRadius = 1f;
|
|
|
|
public bool CalcFromSize;
|
|
|
|
public int Dpi = 300;
|
|
|
|
public float Width = 24f;
|
|
|
|
public int NumberOfGrabs;
|
|
|
|
public float EstimatedTime;
|
|
|
|
public int GrabWidthWillBe;
|
|
|
|
public int GrabHeightWillBe;
|
|
|
|
public bool UseCoroutine;
|
|
|
|
private float mleft;
|
|
|
|
private float mright;
|
|
|
|
private float mtop;
|
|
|
|
private float mbottom;
|
|
|
|
private int sampcount;
|
|
|
|
private Vector2[] poisson;
|
|
|
|
private Texture2D grabtex;
|
|
|
|
private Color[,] accbuf;
|
|
|
|
private Color[,] blendbuf;
|
|
|
|
private byte[] output1;
|
|
|
|
private Color[] outputjpg;
|
|
|
|
private AnisotropicFiltering filtering;
|
|
|
|
private MGBlendTable blendtable;
|
|
|
|
private int DOFSamples;
|
|
|
|
private Vector3 camfor;
|
|
|
|
private Vector3 campos;
|
|
|
|
private Matrix4x4 camtm;
|
|
|
|
public IMGFormat OutputFormat = IMGFormat.Jpg;
|
|
|
|
public float Quality = 75f;
|
|
|
|
public bool uploadGrabs;
|
|
|
|
public string m_URL = "http://www.west-racing.com/uploadtest1.php";
|
|
|
|
private void CalcDOFInfo(Camera camera)
|
|
{
|
|
camtm = camera.transform.localToWorldMatrix;
|
|
campos = camera.transform.position;
|
|
camfor = camera.transform.forward;
|
|
}
|
|
|
|
private void ChangeDOFPos(int segment)
|
|
{
|
|
float f = (float)segment / (float)totalSegments * (float)Math.PI * 2f;
|
|
float num = sampleRadius;
|
|
float x = num * Mathf.Cos(f);
|
|
float y = num * Mathf.Sin(f);
|
|
Vector3 point = new Vector3(x, y, 0f);
|
|
Vector3 vector = camfor * focalDistance;
|
|
Vector3 worldPosition = vector + campos;
|
|
SrcCamera.transform.position = camtm.MultiplyPoint3x4(point);
|
|
SrcCamera.transform.LookAt(worldPosition);
|
|
}
|
|
|
|
private static Matrix4x4 PerspectiveOffCenter(float left, float right, float bottom, float top, float near, float far)
|
|
{
|
|
Matrix4x4 identity = Matrix4x4.identity;
|
|
identity[0, 0] = 2f * near / (right - left);
|
|
identity[1, 1] = 2f * near / (top - bottom);
|
|
identity[0, 2] = (right + left) / (right - left);
|
|
identity[1, 2] = (top + bottom) / (top - bottom);
|
|
identity[2, 2] = (0f - (far + near)) / (far - near);
|
|
identity[2, 3] = (0f - 2f * far * near) / (far - near);
|
|
identity[3, 2] = -1f;
|
|
identity[3, 3] = 0f;
|
|
return identity;
|
|
}
|
|
|
|
private Matrix4x4 CalcProjectionMatrix(float left, float right, float bottom, float top, float near, float far, float xoff, float yoff)
|
|
{
|
|
float num = (right - left) / (float)Screen.width;
|
|
float num2 = (top - bottom) / (float)Screen.height;
|
|
return PerspectiveOffCenter(left - xoff * num, right - xoff * num, bottom - yoff * num2, top - yoff * num2, near, far);
|
|
}
|
|
|
|
private void Cleanup()
|
|
{
|
|
QualitySettings.anisotropicFiltering = filtering;
|
|
}
|
|
|
|
private bool InitGrab(int width, int height, int aasamples)
|
|
{
|
|
blendtable = new MGBlendTable(32, 32, totalSegments, 0.4f, true);
|
|
if (ResUpscale < 1)
|
|
{
|
|
ResUpscale = 1;
|
|
}
|
|
if (AASamples < 1)
|
|
{
|
|
AASamples = 1;
|
|
}
|
|
if (SrcCamera == null)
|
|
{
|
|
SrcCamera = Camera.main;
|
|
}
|
|
if (SrcCamera == null)
|
|
{
|
|
Debug.Log("No Camera set as source and no main camera found in the scene");
|
|
return false;
|
|
}
|
|
CalcDOFInfo(SrcCamera);
|
|
if (OutputFormat == IMGFormat.Tga)
|
|
{
|
|
output1 = new byte[width * ResUpscale * (height * ResUpscale) * 3];
|
|
}
|
|
else
|
|
{
|
|
outputjpg = new Color[width * ResUpscale * (height * ResUpscale)];
|
|
}
|
|
if (output1 != null || outputjpg != null)
|
|
{
|
|
filtering = QualitySettings.anisotropicFiltering;
|
|
QualitySettings.anisotropicFiltering = FilterMode;
|
|
grabtex = new Texture2D(width, height, TextureFormat.RGB24, false);
|
|
if (grabtex != null)
|
|
{
|
|
accbuf = new Color[width, height];
|
|
blendbuf = new Color[width, height];
|
|
if (accbuf != null)
|
|
{
|
|
float a = (1f - Blur) * 0.5f;
|
|
float b = 1f + (Blur - 1f) * 0.5f;
|
|
if (UseJitter)
|
|
{
|
|
poisson = new Vector2[aasamples];
|
|
sampcount = aasamples;
|
|
for (int i = 0; i < aasamples; i++)
|
|
{
|
|
Vector2 vector = new Vector2
|
|
{
|
|
x = Mathf.Lerp(a, b, UnityEngine.Random.value),
|
|
y = Mathf.Lerp(a, b, UnityEngine.Random.value)
|
|
};
|
|
poisson[i] = vector;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int num = (int)Mathf.Sqrt(aasamples);
|
|
if (num < 1)
|
|
{
|
|
num = 1;
|
|
}
|
|
sampcount = num * num;
|
|
poisson = new Vector2[num * num];
|
|
int num2 = 0;
|
|
for (int j = 0; j < num; j++)
|
|
{
|
|
for (int k = 0; k < num; k++)
|
|
{
|
|
float t = (float)k / (float)num;
|
|
float t2 = (float)j / (float)num;
|
|
Vector2 vector2 = new Vector2
|
|
{
|
|
x = Mathf.Lerp(a, b, t),
|
|
y = Mathf.Lerp(a, b, t2)
|
|
};
|
|
poisson[num2++] = vector2;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
Debug.Log("Cant create a large enough texture, Try lower ResUpscale value");
|
|
return false;
|
|
}
|
|
|
|
private Texture2D GrabImage(int samples, float x, float y)
|
|
{
|
|
float num = 1f / (float)ResUpscale;
|
|
for (int i = 0; i < sampcount; i++)
|
|
{
|
|
float num2 = poisson[i].x * num;
|
|
float num3 = poisson[i].y * num;
|
|
float xoff = x + num2;
|
|
float yoff = y + num3;
|
|
SrcCamera.projectionMatrix = CalcProjectionMatrix(mleft, mright, mbottom, mtop, SrcCamera.nearClipPlane, SrcCamera.farClipPlane, xoff, yoff);
|
|
SrcCamera.Render();
|
|
grabtex.ReadPixels(new Rect(0f, 0f, Screen.width, Screen.height), 0, 0);
|
|
grabtex.Apply();
|
|
if (i == 0)
|
|
{
|
|
for (int j = 0; j < Screen.height; j++)
|
|
{
|
|
for (int k = 0; k < Screen.width; k++)
|
|
{
|
|
accbuf[k, j] = grabtex.GetPixel(k, j);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
for (int l = 0; l < Screen.height; l++)
|
|
{
|
|
for (int m = 0; m < Screen.width; m++)
|
|
{
|
|
accbuf[m, l] += grabtex.GetPixel(m, l);
|
|
}
|
|
}
|
|
}
|
|
for (int n = 0; n < Screen.height; n++)
|
|
{
|
|
for (int num4 = 0; num4 < Screen.width; num4++)
|
|
{
|
|
grabtex.SetPixel(num4, n, accbuf[num4, n] / sampcount);
|
|
}
|
|
}
|
|
grabtex.Apply();
|
|
return grabtex;
|
|
}
|
|
|
|
private void GrabAA(float x, float y)
|
|
{
|
|
float num = 1f / (float)ResUpscale;
|
|
for (int i = 0; i < Screen.height; i++)
|
|
{
|
|
for (int j = 0; j < Screen.width; j++)
|
|
{
|
|
accbuf[j, i] = Color.black;
|
|
}
|
|
}
|
|
for (int k = 0; k < sampcount; k++)
|
|
{
|
|
float num2 = poisson[k].x * num;
|
|
float num3 = poisson[k].y * num;
|
|
float xoff = x + num2;
|
|
float yoff = y + num3;
|
|
SrcCamera.projectionMatrix = CalcProjectionMatrix(mleft, mright, mbottom, mtop, SrcCamera.nearClipPlane, SrcCamera.farClipPlane, xoff, yoff);
|
|
SrcCamera.Render();
|
|
grabtex.ReadPixels(new Rect(0f, 0f, Screen.width, Screen.height), 0, 0);
|
|
grabtex.Apply();
|
|
for (int l = 0; l < Screen.height; l++)
|
|
{
|
|
for (int m = 0; m < Screen.width; m++)
|
|
{
|
|
accbuf[m, l] += grabtex.GetPixel(m, l);
|
|
}
|
|
}
|
|
}
|
|
for (int n = 0; n < Screen.height; n++)
|
|
{
|
|
for (int num4 = 0; num4 < Screen.width; num4++)
|
|
{
|
|
accbuf[num4, n] /= sampcount;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Texture2D GrabImageDOF(int samples, float x, float y)
|
|
{
|
|
for (int i = 0; i < Screen.height; i++)
|
|
{
|
|
for (int j = 0; j < Screen.width; j++)
|
|
{
|
|
blendbuf[j, i] = Color.black;
|
|
}
|
|
}
|
|
for (int k = 0; k < totalSegments; k++)
|
|
{
|
|
ChangeDOFPos(k);
|
|
GrabAA(x, y);
|
|
blendtable.BlendImages(blendbuf, accbuf, Screen.width, Screen.height, k);
|
|
}
|
|
return grabtex;
|
|
}
|
|
|
|
private void DoGrabTGA()
|
|
{
|
|
if (!InitGrab(Screen.width, Screen.height, AASamples))
|
|
{
|
|
return;
|
|
}
|
|
mtop = SrcCamera.nearClipPlane * Mathf.Tan(SrcCamera.fieldOfView * 0.5f * ((float)Math.PI / 180f));
|
|
mbottom = 0f - mtop;
|
|
mleft = mbottom * SrcCamera.aspect;
|
|
mright = mtop * SrcCamera.aspect;
|
|
int width = Screen.width;
|
|
int height = Screen.height;
|
|
if (AASamples < 1)
|
|
{
|
|
AASamples = 1;
|
|
}
|
|
int num = 0;
|
|
for (int i = 0; i < ResUpscale; i++)
|
|
{
|
|
float y = (float)i / (float)ResUpscale;
|
|
for (int j = 0; j < ResUpscale; j++)
|
|
{
|
|
num++;
|
|
float x = (float)j / (float)ResUpscale;
|
|
Texture2D texture2D;
|
|
if (UseDOF)
|
|
{
|
|
texture2D = GrabImageDOF(AASamples, x, y);
|
|
for (int k = 0; k < Screen.height; k++)
|
|
{
|
|
int num2 = (ResUpscale - i + k * ResUpscale - 1) * (width * ResUpscale);
|
|
for (int l = 0; l < Screen.width; l++)
|
|
{
|
|
Color color = blendbuf[l, k];
|
|
int num3 = (num2 + (ResUpscale - j + l * ResUpscale - 1)) * 3;
|
|
output1[num3] = (byte)(color.b * 255f);
|
|
output1[num3 + 1] = (byte)(color.g * 255f);
|
|
output1[num3 + 2] = (byte)(color.r * 255f);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
texture2D = GrabImage(AASamples, x, y);
|
|
for (int m = 0; m < Screen.height; m++)
|
|
{
|
|
int num4 = (ResUpscale - i + m * ResUpscale - 1) * (width * ResUpscale);
|
|
for (int n = 0; n < Screen.width; n++)
|
|
{
|
|
Color pixel = texture2D.GetPixel(n, m);
|
|
int num5 = (num4 + (ResUpscale - j + n * ResUpscale - 1)) * 3;
|
|
output1[num5] = (byte)(pixel.b * 255f);
|
|
output1[num5 + 1] = (byte)(pixel.g * 255f);
|
|
output1[num5 + 2] = (byte)(pixel.r * 255f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
string text = string.Empty;
|
|
if (Enviro != null && Enviro.Length > 0)
|
|
{
|
|
text = Environment.GetEnvironmentVariable(Enviro);
|
|
}
|
|
string text2 = text + Path + SaveName + " " + width * ResUpscale + "x" + height * ResUpscale + " " + DateTime.Now.ToString(Format);
|
|
SaveTGA(text2 + ".tga", width * ResUpscale, height * ResUpscale, output1);
|
|
SrcCamera.ResetProjectionMatrix();
|
|
Cleanup();
|
|
}
|
|
|
|
private void DoGrabJPG()
|
|
{
|
|
if (!InitGrab(Screen.width, Screen.height, AASamples))
|
|
{
|
|
return;
|
|
}
|
|
mtop = SrcCamera.nearClipPlane * Mathf.Tan(SrcCamera.fieldOfView * 0.5f * ((float)Math.PI / 180f));
|
|
mbottom = 0f - mtop;
|
|
mleft = mbottom * SrcCamera.aspect;
|
|
mright = mtop * SrcCamera.aspect;
|
|
int width = Screen.width;
|
|
int height = Screen.height;
|
|
if (AASamples < 1)
|
|
{
|
|
AASamples = 1;
|
|
}
|
|
int num = 0;
|
|
for (int i = 0; i < ResUpscale; i++)
|
|
{
|
|
float y = (float)i / (float)ResUpscale;
|
|
for (int j = 0; j < ResUpscale; j++)
|
|
{
|
|
num++;
|
|
float x = (float)j / (float)ResUpscale;
|
|
Texture2D texture2D;
|
|
if (UseDOF)
|
|
{
|
|
texture2D = GrabImageDOF(AASamples, x, y);
|
|
for (int k = 0; k < Screen.height; k++)
|
|
{
|
|
int num2 = (ResUpscale - i + k * ResUpscale - 1) * (width * ResUpscale);
|
|
for (int l = 0; l < Screen.width; l++)
|
|
{
|
|
Color color = blendbuf[l, k];
|
|
int num3 = num2 + (ResUpscale - j + l * ResUpscale - 1);
|
|
outputjpg[num3] = color;
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
texture2D = GrabImage(AASamples, x, y);
|
|
for (int m = 0; m < Screen.height; m++)
|
|
{
|
|
int num4 = (ResUpscale - i + m * ResUpscale - 1) * (width * ResUpscale);
|
|
for (int n = 0; n < Screen.width; n++)
|
|
{
|
|
Color pixel = texture2D.GetPixel(n, m);
|
|
int num5 = num4 + (ResUpscale - j + n * ResUpscale - 1);
|
|
outputjpg[num5] = pixel;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
string text = string.Empty;
|
|
if (Enviro != null && Enviro.Length > 0)
|
|
{
|
|
text = Environment.GetEnvironmentVariable(Enviro);
|
|
}
|
|
if (uploadGrabs)
|
|
{
|
|
string text2 = SaveName + " " + width * ResUpscale + "x" + height * ResUpscale + " " + DateTime.Now.ToString(Format);
|
|
UploadJPG(text2 + ".jpg", width * ResUpscale, height * ResUpscale, outputjpg);
|
|
}
|
|
else
|
|
{
|
|
string text3 = text + Path + SaveName + " " + width * ResUpscale + "x" + height * ResUpscale + " " + DateTime.Now.ToString(Format);
|
|
SaveJPG(text3 + ".jpg", width * ResUpscale, height * ResUpscale, outputjpg);
|
|
}
|
|
SrcCamera.ResetProjectionMatrix();
|
|
Cleanup();
|
|
}
|
|
|
|
private void SaveJPG(string filename, int width, int height, Color[] pixels)
|
|
{
|
|
FileStream fileStream = new FileStream(filename, FileMode.Create);
|
|
if (fileStream != null)
|
|
{
|
|
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
|
|
if (binaryWriter != null)
|
|
{
|
|
Quality = Mathf.Clamp(Quality, 0f, 100f);
|
|
JPGEncoder jPGEncoder = new JPGEncoder(pixels, width, height, Quality);
|
|
jPGEncoder.doEncoding();
|
|
byte[] bytes = jPGEncoder.GetBytes();
|
|
binaryWriter.Write(bytes);
|
|
binaryWriter.Close();
|
|
}
|
|
fileStream.Close();
|
|
}
|
|
}
|
|
|
|
private void UploadJPG(string filename, int width, int height, Color[] pixels)
|
|
{
|
|
Quality = Mathf.Clamp(Quality, 0f, 100f);
|
|
JPGEncoder jPGEncoder = new JPGEncoder(pixels, width, height, Quality);
|
|
jPGEncoder.doEncoding();
|
|
byte[] bytes = jPGEncoder.GetBytes();
|
|
UploadFile(bytes, m_URL, filename);
|
|
}
|
|
|
|
private void SaveTGA(string filename, int width, int height, byte[] pixels)
|
|
{
|
|
FileStream fileStream = new FileStream(filename, FileMode.Create);
|
|
if (fileStream == null)
|
|
{
|
|
return;
|
|
}
|
|
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
|
|
if (binaryWriter != null)
|
|
{
|
|
binaryWriter.Write((short)0);
|
|
binaryWriter.Write((byte)2);
|
|
binaryWriter.Write(0);
|
|
binaryWriter.Write(0);
|
|
binaryWriter.Write((byte)0);
|
|
binaryWriter.Write((short)width);
|
|
binaryWriter.Write((short)height);
|
|
binaryWriter.Write((byte)24);
|
|
binaryWriter.Write((byte)0);
|
|
for (int i = 0; i < pixels.Length; i++)
|
|
{
|
|
binaryWriter.Write(pixels[i]);
|
|
}
|
|
binaryWriter.Close();
|
|
}
|
|
fileStream.Close();
|
|
}
|
|
|
|
private void CalcUpscale()
|
|
{
|
|
float num = Width / ((float)Screen.width / (float)Dpi);
|
|
ResUpscale = (int)num;
|
|
GrabWidthWillBe = Screen.width * ResUpscale;
|
|
GrabHeightWillBe = Screen.height * ResUpscale;
|
|
}
|
|
|
|
private void CalcEstimate()
|
|
{
|
|
NumberOfGrabs = ResUpscale * ResUpscale * AASamples;
|
|
if (UseDOF)
|
|
{
|
|
NumberOfGrabs *= totalSegments;
|
|
}
|
|
EstimatedTime = (float)NumberOfGrabs * 0.41f;
|
|
}
|
|
|
|
private IEnumerator GrabCoroutine()
|
|
{
|
|
yield return new WaitForEndOfFrame();
|
|
if (OutputFormat == IMGFormat.Tga)
|
|
{
|
|
DoGrabTGA();
|
|
}
|
|
else
|
|
{
|
|
DoGrabJPG();
|
|
}
|
|
yield return null;
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
if (!Input.GetKeyDown(GrabKey))
|
|
{
|
|
return;
|
|
}
|
|
if (CalcFromSize)
|
|
{
|
|
CalcUpscale();
|
|
}
|
|
CalcEstimate();
|
|
if (UseCoroutine)
|
|
{
|
|
StartCoroutine(GrabCoroutine());
|
|
return;
|
|
}
|
|
float realtimeSinceStartup = Time.realtimeSinceStartup;
|
|
if (OutputFormat == IMGFormat.Tga)
|
|
{
|
|
DoGrabTGA();
|
|
}
|
|
else
|
|
{
|
|
DoGrabJPG();
|
|
}
|
|
Debug.Log("Took " + (Time.realtimeSinceStartup - realtimeSinceStartup).ToString("0.00000000") + "s");
|
|
}
|
|
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (CalcFromSize)
|
|
{
|
|
CalcUpscale();
|
|
}
|
|
CalcEstimate();
|
|
}
|
|
|
|
private IEnumerator UploadFileCo(byte[] data, string uploadURL, string filename)
|
|
{
|
|
WWWForm postForm = new WWWForm();
|
|
Debug.Log("uploading " + filename);
|
|
postForm.AddField("action", "Upload Image");
|
|
postForm.AddBinaryData("theFile", data, filename, "images/jpg");
|
|
Debug.Log("url " + uploadURL);
|
|
WWW upload = new WWW(uploadURL, postForm);
|
|
yield return upload;
|
|
Debug.Log("upload done :" + upload.text);
|
|
Debug.Log("Error during upload: " + upload.error);
|
|
}
|
|
|
|
private void UploadFile(byte[] data, string uploadURL, string filename)
|
|
{
|
|
Debug.Log("Start upload");
|
|
StartCoroutine(UploadLevel(data, uploadURL, filename));
|
|
Debug.Log("len " + data.Length);
|
|
}
|
|
|
|
private IEnumerator UploadLevel(byte[] data, string uploadURL, string filename)
|
|
{
|
|
WWWForm form = new WWWForm();
|
|
form.AddField("action", "level upload");
|
|
form.AddField("file", "file");
|
|
form.AddBinaryData("file", data, filename, "images/jpg");
|
|
Debug.Log("url " + uploadURL);
|
|
WWW w = new WWW(uploadURL, form);
|
|
yield return w;
|
|
if (w.error != null)
|
|
{
|
|
MonoBehaviour.print("error");
|
|
MonoBehaviour.print(w.error);
|
|
}
|
|
else if (w.uploadProgress == 1f && w.isDone)
|
|
{
|
|
yield return new WaitForSeconds(5f);
|
|
}
|
|
}
|
|
}
|