diff --git a/README.md b/README.md index ac83ad9..4085cf1 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,29 @@ # ZDRay baking utility for GZDoom -ZDRay is a node and lightmap generator. It is based on zdbsp for the node generation and dlight for the lightmap generation. +ZDRay is a node and lightmap generator for GZDoom. ZDRay is intended as a drop-in replacement for zdbsp, with the additional feature +that it can also bake lights. Once ZDRay has processed the level WAD it is ready to be used by GZDoom. -Special thanks to Randi Heit, Samuel Villarreal, Christoph Oelckers and anyone else involved in creating or maintaining those tools. +ZDRay is based on zdbsp for the node generation and originally used dlight for the lightmap generation. Special thanks to Randi Heit, +Samuel Villarreal, Christoph Oelckers and anyone else involved in creating or maintaining those tools. + +The ray tracing code has been completely rewritten since. It now supports bounces and can do the ray tracing on the GPU. ## ZDRay UDMF properties
+thing // ZDRayInfo (zdray properties for the map)
+{
+	type = 9890;
+	suncolor = <int> (color)
+	sundirx = <float> (X direction for the sun)
+	sundiry = <float> (Y direction for the sun)
+	sundirz = <float> (Z direction for the sun)
+	sampledistance = <int> (default: 8, map units each lightmap texel covers, must be in powers of two)
+	bounces = <int> (default: 1, how many times light bounces off walls)
+	gridsize = <float> (default: 32, grid density for the automatic light probes)
+}
+
 thing // StaticLight (point or spot light to be baked into the lightmap)
 {
 	lightcolor = <int> (color)
@@ -22,23 +38,14 @@ thing // LightProbe (light sampling point for actors)
 	type = 9875;
 }
 
-thing // Sunlight (sunlight properties for the map)
-{
-	type = 9890;
-	suncolor = <int> (color)
-	sundirx = <float> (X direction for the sun)
-	sundiry = <float> (Y direction for the sun)
-	sundirz = <float> (Z direction for the sun)
-}
-
-linedef // Line surface emitting
+linedef // Line emissive surface
 {
 	lightcolor = <int> (color, default: white)
 	lightintensity = <float> (default: 1)
 	lightdistance = <float> (default: 0, no light)
 }
 
-sector // Sector planes emitting light
+sector // Sector plane emissive surface
 {
 	lightcolorfloor = <int> (color, default: white)
 	lightintensityfloor = <float> (default: 1)
diff --git a/src/level/doomdata.h b/src/level/doomdata.h
index e74b41b..734001d 100644
--- a/src/level/doomdata.h
+++ b/src/level/doomdata.h
@@ -387,8 +387,11 @@ struct FLevel
 	TArray SurfaceLights;
 	TArray ThingLightProbes;
 
-	Vec3 defaultSunColor = Vec3(1, 1, 1);
-	Vec3 defaultSunDirection = Vec3(0.45f, 0.3f, 0.9f);
+	Vec3 defaultSunColor;
+	Vec3 defaultSunDirection;
+	int Samples;
+	int LightBounce;
+	float GridSize;
 
 	void FindMapBounds ();
 	void RemoveExtraLines ();
diff --git a/src/level/level.cpp b/src/level/level.cpp
index 911a8cd..93ba7c7 100644
--- a/src/level/level.cpp
+++ b/src/level/level.cpp
@@ -30,7 +30,6 @@
 #endif
 
 extern int LMDims;
-extern int Samples;
 extern bool CPURaytrace;
 
 extern void ShowView (FLevel *level);
@@ -693,7 +692,7 @@ void FProcessor::BuildNodes()
 void FProcessor::BuildLightmaps()
 {
 	Level.SetupLights();
-	LightmapMesh = std::make_unique(Level, Samples, LMDims);
+	LightmapMesh = std::make_unique(Level, Level.Samples, LMDims);
 
 	if (CPURaytrace)
 	{
diff --git a/src/level/level_light.cpp b/src/level/level_light.cpp
index 2192ca2..682566d 100644
--- a/src/level/level_light.cpp
+++ b/src/level/level_light.cpp
@@ -84,6 +84,13 @@ void FLevel::SetupLights()
 		}
 	}
 
+	// GG to whoever memset'ed FLevel
+	defaultSunColor = Vec3(1, 1, 1);
+	defaultSunDirection = Vec3(0.45f, 0.3f, 0.9f);
+	Samples = 8;
+	LightBounce = 1;
+	GridSize = 32.0f;
+
 	for (int i = 0; i < (int)Things.Size(); ++i)
 	{
 		IntThing* thing = &Things[i];
@@ -91,7 +98,7 @@ void FLevel::SetupLights()
 		{
 			ThingLightProbes.Push(i);
 		}
-		else if (thing->type == 9890) // Sunlight
+		else if (thing->type == 9890) // ZDRayInfo
 		{
 			uint32_t lightcolor = 0xffffff;
 			Vec3 sundir(0.0f, 0.0f, 0.0f);
@@ -116,6 +123,25 @@ void FLevel::SetupLights()
 				{
 					sundir.z = atof(key.value);
 				}
+				else if (!stricmp(key.key, "sampledistance"))
+				{
+					Samples = atoi(key.value);
+					if (Samples <= 0) Samples = 1;
+					if (Samples > 128) Samples = 128;
+					Samples = Math::RoundPowerOfTwo(Samples);
+				}
+				else if (!stricmp(key.key, "bounces"))
+				{
+					LightBounce = atoi(key.value);
+					if (LightBounce < 0) LightBounce = 0;
+					if (LightBounce > 8) LightBounce = 8;
+				}
+				else if (!stricmp(key.key, "gridsize"))
+				{
+					GridSize = atof(key.value);
+					if (GridSize < 0.f) GridSize = 0.f;
+					if (GridSize > 1024.f) GridSize = 1024.f;
+				}
 			}
 
 			if (Vec3::Dot(sundir, sundir) > 0.01f)
diff --git a/src/lightmap/cpuraytracer.cpp b/src/lightmap/cpuraytracer.cpp
index 4519e51..9bdb108 100644
--- a/src/lightmap/cpuraytracer.cpp
+++ b/src/lightmap/cpuraytracer.cpp
@@ -12,7 +12,6 @@
 #include 
 #include 
 
-extern int LightBounce;
 extern bool VKDebug;
 
 CPURaytracer::CPURaytracer()
@@ -59,7 +58,7 @@ void CPURaytracer::Raytrace(LevelMesh* level)
 	CreateHemisphereVectors();
 	CreateLights();
 
-	printf("Ray tracing with %d bounce(s)\n", LightBounce);
+	printf("Ray tracing with %d bounce(s)\n", mesh->map->LightBounce);
 
 	Worker::RunJob((int)tasks.size(), [=](int id) { RaytraceTask(tasks[id]); });
 
@@ -107,7 +106,7 @@ void CPURaytracer::RaytraceTask(const CPUTraceTask& task)
 		state.HemisphereVec = HemisphereVectors[state.SampleIndex];
 		RunBounceTrace(state);
 
-		for (int bounce = 0; bounce < LightBounce && !state.EndTrace; bounce++)
+		for (int bounce = 0; bounce < mesh->map->LightBounce && !state.EndTrace; bounce++)
 		{
 			state.SampleCount = coverageSampleCount;
 			RunLightTrace(state);
diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp
index c71e3ae..2c1f767 100644
--- a/src/lightmap/gpuraytracer.cpp
+++ b/src/lightmap/gpuraytracer.cpp
@@ -21,7 +21,6 @@
 #include "glsl_rmiss_light.h"
 #include "glsl_rmiss_sun.h"
 
-extern int LightBounce;
 extern bool VKDebug;
 
 GPURaytracer::GPURaytracer()
@@ -86,7 +85,7 @@ void GPURaytracer::Raytrace(LevelMesh* level)
 		HemisphereVectors.push_back(H);
 	}
 
-	printf("Ray tracing with %d bounce(s)\n", LightBounce);
+	printf("Ray tracing with %d bounce(s)\n", mesh->map->LightBounce);
 
 	size_t maxTasks = (size_t)rayTraceImageSize * rayTraceImageSize;
 	for (size_t startTask = 0; startTask < tasks.size(); startTask += maxTasks)
@@ -119,7 +118,7 @@ void GPURaytracer::Raytrace(LevelMesh* level)
 			uniforms.HemisphereVec = HemisphereVectors[uniforms.SampleIndex];
 			RunTrace(uniforms, rgenBounceRegion);
 
-			for (int bounce = 0; bounce < LightBounce; bounce++)
+			for (int bounce = 0; bounce < mesh->map->LightBounce; bounce++)
 			{
 				uniforms.SampleCount = coverageSampleCount;
 				RunTrace(uniforms, rgenLightRegion);
diff --git a/src/lightmap/surfaces.cpp b/src/lightmap/surfaces.cpp
index 32fc126..1238a69 100644
--- a/src/lightmap/surfaces.cpp
+++ b/src/lightmap/surfaces.cpp
@@ -34,8 +34,6 @@
 #include "pngwriter.h"
 #include 
 
-extern float GridSize;
-
 #ifdef _MSC_VER
 #pragma warning(disable: 4267) // warning C4267: 'argument': conversion from 'size_t' to 'int', possible loss of data
 #pragma warning(disable: 4244) // warning C4244: '=': conversion from '__int64' to 'int', possible loss of data
@@ -392,12 +390,12 @@ void LevelMesh::CreateLightProbes(FLevel& map)
 	float maxX = std::floor(map.MaxX / 65536.0f) + 1.0f;
 	float maxY = std::floor(map.MaxY / 65536.0f) + 1.0f;
 
-	float halfGridSize = GridSize * 0.5f;
-	float doubleGridSize = GridSize * 2.0f;
+	float halfGridSize = map.GridSize * 0.5f;
+	float doubleGridSize = map.GridSize * 2.0f;
 
-	for (float y = minY; y < maxY; y += GridSize)
+	for (float y = minY; y < maxY; y += map.GridSize)
 	{
-		for (float x = minX; x < maxX; x += GridSize)
+		for (float x = minX; x < maxX; x += map.GridSize)
 		{
 			MapSubsectorEx* ssec = map.PointInSubSector((int)x, (int)y);
 			IntSector* sec = ssec ? map.GetSectorFromSubSector(ssec) : nullptr;
diff --git a/src/main.cpp b/src/main.cpp
index 7214d87..763b2da 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -115,11 +115,8 @@ bool			 HaveSSE1, HaveSSE2;
 int				 SSELevel;
 int				 NumThreads = 0;
 int				 LMDims = 1024;
-int				 Samples = 8;
 bool			 CPURaytrace = false;
 bool			 VKDebug = false;
-int				 LightBounce = 1;
-float			 GridSize = 32.0f;
 
 // PRIVATE DATA DEFINITIONS ------------------------------------------------
 
@@ -155,16 +152,13 @@ static option long_opts[] =
 	{"no-sse2",			no_argument,		0,  1003},
 	{"comments",		no_argument,		0,	'c'},
 	{"threads",			required_argument,	0,	'j'},
-	{"samples",			required_argument,	0,	'Q'},
 	{"size",			required_argument,	0,	'S'},
 	{"cpu-raytrace",	no_argument,		0,	'C'},
-	{"bounce",			required_argument,	0,	'B'},
-	{"gridsize",		required_argument,	0,	'i'},
 	{"vkdebug",			no_argument,		0,	'D'},
 	{0,0,0,0}
 };
 
-static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5cj:Q:S:CD";
+static const char short_opts[] = "wVgGvbNrReEm:o:f:p:s:d:PqtzZXx5cj:S:CD";
 
 // CODE --------------------------------------------------------------------
 
@@ -439,12 +433,6 @@ static void ParseArgs(int argc, char **argv)
 		case 'j':
 			NumThreads = atoi(optarg);
 			break;
-		case 'Q':
-			Samples = atoi(optarg);
-			if (Samples <= 0) Samples = 1;
-			if (Samples > 128) Samples = 128;
-			Samples = Math::RoundPowerOfTwo(Samples);
-			break;
 		case 'S':
 			LMDims = atoi(optarg);
 			if (LMDims <= 0) LMDims = 1;
@@ -457,15 +445,6 @@ static void ParseArgs(int argc, char **argv)
 		case 'D':
 			VKDebug = true;
 			break;
-		case 'B':
-			LightBounce = atoi(optarg);
-			if (LightBounce < 0) LightBounce = 0;
-			if (LightBounce > 8) LightBounce = 8;
-			break;
-		case 'i':
-			GridSize = std::stof(optarg);
-			if (GridSize < 0.f) GridSize = 0.f;
-			break;
 		case 1000:
 			ShowUsage();
 			exit(0);
@@ -508,15 +487,9 @@ static void ShowUsage()
 		"  -d, --diagonal-cost=NNN  Cost for avoiding diagonal splitters (default %d)\n"
 		"  -P, --no-polyobjs        Do not check for polyobject subsector splits\n"
 		"  -j, --threads=NNN        Number of threads used for raytracing (default %d)\n"
-		"  -Q, --samples=NNN        Set texel sampling size (lowest = higher quaility but\n"
-		"                           slow compile time) must be in powers of two (default %d)\n"
 		"  -S, --size=NNN           lightmap texture dimensions for width and height\n"
 		"                           must be in powers of two (1, 2, 4, 8, 16, etc)\n"
 		"  -C, --cpu-raytrace       Use the CPU for ray tracing\n"
-		"  -B, --bounce=NNN         Number of indirect light bounces (default %d, max 8)\n"
-		"  -i, --gridsize=NNN       Automatic light probe grid size, floating point\n"
-		"                           Lower values increase granularity at the expense of performance\n"
-		"                           Recommended: 32.0, 64.0, 128.0, etc (default %.1f)\n"
 		"  -D, --vkdebug            Print messages from the vulkan validation layer\n"
 		"  -w, --warn               Show warning messages\n"
 #if HAVE_TIMING
@@ -531,9 +504,6 @@ static void ShowUsage()
 		, SplitCost
 		, AAPreference
 		, (int)std::thread::hardware_concurrency()
-		, Samples
-		, LightBounce
-		, GridSize
 	);
 }