From f3c55c01c86fbc48e92ed401c4ab618143b7e152 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Sat, 20 Jan 2018 16:28:24 +0100
Subject: [PATCH] Add material definition to GLDEFS

---
 src/g_shared/a_dynlightdata.cpp |   8 ++-
 src/gl/textures/gl_texture.cpp  | 111 ++++++++++++++++++++++++++++++++
 src/textures/textures.h         |  10 +++
 3 files changed, 128 insertions(+), 1 deletion(-)

diff --git a/src/g_shared/a_dynlightdata.cpp b/src/g_shared/a_dynlightdata.cpp
index fcdbcd3d1..2c2a6bd08 100644
--- a/src/g_shared/a_dynlightdata.cpp
+++ b/src/g_shared/a_dynlightdata.cpp
@@ -56,6 +56,7 @@
 int ScriptDepth;
 void gl_InitGlow(FScanner &sc);
 void gl_ParseBrightmap(FScanner &sc, int);
+void gl_ParseMaterial(FScanner &sc, int);
 void gl_DestroyUserShaders();
 void gl_ParseHardwareShader(FScanner &sc, int deflump);
 void gl_ParseDetailTexture(FScanner &sc);
@@ -906,7 +907,8 @@ static const char *CoreKeywords[]=
    "hardwareshader",
    "detail",
    "#include",
-   NULL
+   "material",
+   nullptr
 };
 
 
@@ -928,6 +930,7 @@ enum
    TAG_HARDWARESHADER,
    TAG_DETAIL,
    TAG_INCLUDE,
+   TAG_MATERIAL
 };
 
 
@@ -1285,6 +1288,9 @@ static void DoParseDefs(FScanner &sc, int workingLump)
 		case TAG_BRIGHTMAP:
 			gl_ParseBrightmap(sc, workingLump);
 			break;
+		case TAG_MATERIAL:
+			gl_ParseMaterial(sc, workingLump);
+			break;
 		case TAG_HARDWARESHADER:
 			gl_ParseHardwareShader(sc, workingLump);
 			break;
diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp
index ddfd7ecc9..e7e459186 100644
--- a/src/gl/textures/gl_texture.cpp
+++ b/src/gl/textures/gl_texture.cpp
@@ -195,6 +195,11 @@ FTexture::MiscGLInfo::MiscGLInfo() throw()
 	Material[1] = Material[0] = NULL;
 	SystemTexture[1] = SystemTexture[0] = NULL;
 	Brightmap = NULL;
+	Normal = NULL;
+	Specular = NULL;
+	Metallic = NULL;
+	Roughness = NULL;
+	AmbientOcclusion = NULL;
 }
 
 FTexture::MiscGLInfo::~MiscGLInfo()
@@ -542,6 +547,112 @@ int FBrightmapTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotat
 	return 0;
 }
 
+//==========================================================================
+//
+// Parses a material definition
+//
+//==========================================================================
+
+void gl_ParseMaterial(FScanner &sc, int deflump)
+{
+	int type = FTexture::TEX_Any;
+	bool disable_fullbright = false;
+	bool disable_fullbright_specified = false;
+	bool thiswad = false;
+	bool iwad = false;
+
+	FTexture *textures[6];
+	const char *keywords[7] = { "brightmap", "normal", "specular", "metallic", "roughness", "ao", nullptr };
+	const char *notFound[6] = { "Brightmap", "Normalmap", "Specular texture", "Metallic texture", "Roughness texture", "Ambient occlusion texture" };
+	memset(textures, 0, sizeof(textures));
+
+	sc.MustGetString();
+	if (sc.Compare("texture")) type = FTexture::TEX_Wall;
+	else if (sc.Compare("flat")) type = FTexture::TEX_Flat;
+	else if (sc.Compare("sprite")) type = FTexture::TEX_Sprite;
+	else sc.UnGet();
+
+	sc.MustGetString();
+	FTextureID no = TexMan.CheckForTexture(sc.String, type, FTextureManager::TEXMAN_TryAny | FTextureManager::TEXMAN_Overridable);
+	FTexture *tex = TexMan[no];
+
+	sc.MustGetToken('{');
+	while (!sc.CheckToken('}'))
+	{
+		sc.MustGetString();
+		if (sc.Compare("disablefullbright"))
+		{
+			// This can also be used without a brightness map to disable
+			// fullbright in rotations that only use brightness maps on
+			// other angles.
+			disable_fullbright = true;
+			disable_fullbright_specified = true;
+		}
+		else if (sc.Compare("thiswad"))
+		{
+			// only affects textures defined in the WAD containing the definition file.
+			thiswad = true;
+		}
+		else if (sc.Compare ("iwad"))
+		{
+			// only affects textures defined in the IWAD.
+			iwad = true;
+		}
+		else
+		{
+			for (int i = 0; keywords[i] != nullptr; i++)
+			{
+				if (sc.Compare (keywords[i]))
+				{
+					sc.MustGetString();
+					if (textures[i])
+						Printf("Multiple %s definitions in texture %s\n", keywords[i], tex? tex->Name.GetChars() : "(null)");
+					textures[i] = TexMan.FindTexture(sc.String, FTexture::TEX_Any, FTextureManager::TEXMAN_TryAny);
+					if (!textures[i])
+						Printf("%s '%s' not found in texture '%s'\n", notFound[i], sc.String, tex? tex->Name.GetChars() : "(null)");
+					break;
+				}
+			}
+		}
+	}
+	if (!tex)
+	{
+		return;
+	}
+	if (thiswad || iwad)
+	{
+		bool useme = false;
+		int lumpnum = tex->GetSourceLump();
+
+		if (lumpnum != -1)
+		{
+			if (iwad && Wads.GetLumpFile(lumpnum) <= Wads.GetIwadNum()) useme = true;
+			if (thiswad && Wads.GetLumpFile(lumpnum) == deflump) useme = true;
+		}
+		if (!useme) return;
+	}
+
+	FTexture **bindings[6] =
+	{
+		&tex->gl_info.Brightmap,
+		&tex->gl_info.Normal,
+		&tex->gl_info.Specular,
+		&tex->gl_info.Metallic,
+		&tex->gl_info.Roughness,
+		&tex->gl_info.AmbientOcclusion
+	};
+	for (int i = 0; keywords[i] != nullptr; i++)
+	{
+		if (textures[i])
+		{
+			textures[i]->bMasked = false;
+			*bindings[i] = textures[i];
+		}
+	}
+
+	if (disable_fullbright_specified)
+		tex->gl_info.bDisableFullbright = disable_fullbright;
+}
 
 //==========================================================================
 //
diff --git a/src/textures/textures.h b/src/textures/textures.h
index 539d38c43..72501e492 100644
--- a/src/textures/textures.h
+++ b/src/textures/textures.h
@@ -328,6 +328,11 @@ protected:
 		Rotations = other->Rotations;
 		gl_info = other->gl_info;
 		gl_info.Brightmap = NULL;
+		gl_info.Normal = NULL;
+		gl_info.Specular = NULL;
+		gl_info.Metallic = NULL;
+		gl_info.Roughness = NULL;
+		gl_info.AmbientOcclusion = NULL;
 		gl_info.areas = NULL;
 	}
 
@@ -362,6 +367,11 @@ public:
 		FMaterial *Material[2];
 		FGLTexture *SystemTexture[2];
 		FTexture *Brightmap;
+		FTexture *Normal;						// Normal map texture
+		FTexture *Specular;						// Specular light texture for the diffuse+normal+specular light model
+		FTexture *Metallic;						// Metalness texture for the physically based rendering (PBR) light model
+		FTexture *Roughness;					// Roughness texture for PBR
+		FTexture *AmbientOcclusion;				// Ambient occlusion texture for PBR
 		PalEntry GlowColor;
 		int GlowHeight;
 		FloatRect *areas;