#include <stdio.h>
#include <string.h>
#include <stdlib.h>

char shaders[][64] =
{
	"fixedemu",
	"fixedemu_flat",
	"q3terrain",
	"altwater",
	"bloom_blur",
	"bloom_filter",
	"bloom_final",
	"colourtint",
	"crepuscular_opaque",
	"crepuscular_rays",
	"crepuscular_sky",
	"depthonly",
	"default2d",
	"default2danim",
	"defaultadditivesprite",
	"defaultskin",
	"defaultsky",
	"defaultskybox",
	"defaultfill",
	"defaultsprite",
	"defaultwall",
	"defaultwarp",
	"defaultgammacb",
	"drawflat_wall",
	"wireframe",
	"itemtimer",
	"lpp_depthnorm",
	"lpp_light",
	"lpp_wall",
	"postproc_fisheye",
	"postproc_panorama",
	"postproc_laea",
	"postproc_stereographic",
	"postproc_equirectangular",
	"postproc_panini",
	"postproc_ascii",
	"fxaa",
	"underwaterwarp",
	"menutint",
	"terrain",
	"rtlight",
	"rq_rtlight",
	""
};

void dumpprogstring(FILE *out, FILE *src)
{
	int j;
	char line[1024];

	while(fgets(line, sizeof(line), src))
	{
		j = 0;
		while (line[j] == ' ' || line[j] == '\t')
			j++;
		if ((line[j] == '/' && line[j] == '/') || line[j] == '\r' || line[j] == '\n')
		{
			for (; line[j]; j++)
			{
				if (line[j] != '\r')
					fputc(line[j], out);
			}
		}
		else
		{
			fputc('\"', out);				
			while (line[j] && line[j] != '\r' && line[j] != '\n')
			{
				if (line[j] == '\t')
					fputc(' ', out);
				else if (line[j] == '\"')
				{
					fputc('\\', out);
					fputc(line[j], out);
				}
				else
					fputc(line[j], out);
				j++;
			}
			fputs("\\n\"\n", out);
		}
	}
	fflush(out);
}
void dumpprogblob(FILE *out, FILE *src)
{
	unsigned char *buf;
	unsigned int size;
	fseek(src, 0, SEEK_END);
	size = ftell(src);
	fseek(src, 0, SEEK_SET);
	buf = malloc(size);
	fread(buf, size, 1, src);

	size_t totallen, i, linelen;
	totallen = 0;
	linelen = 32;
	fprintf(out, "\"");
	for (i=0;i<size;i++)
	{
		fprintf(out, "\\x%02X",buf[i]);
		if (i % linelen == linelen - 1)
			fprintf(out, "\"\n\"");
	}
	fprintf(out, "\"");
}

static struct shadertype_s
{
	char *abrv;
	char *filepattern;
	char *preprocessor;
	char *rendererapi;
	int apiversion;	//-1 is a binary blob.
} shadertype[] =
{
	{"GL",	"glsl/%s.glsl", 	"GLQUAKE", 	"QR_OPENGL", 		110},	//gl2+
	//{"ES","gles/%s.glsl", 	"GLQUAKE", 	"QR_OPENGL", 		100},	//gles
	{"VK",	"vulkanblobs/%s.fvb",	"VKQUAKE", 	"QR_VULKAN", 		-1},	//vulkan
	{"D9",	"hlsl9/%s.hlsl", 	"D3D9QUAKE", 	"QR_DIRECT3D9", 	9},	//d3d9
	{"D11","hlsl11/%s.hlsl", 	"D3D11QUAKE", 	"QR_DIRECT3D11", 	11},	//d3d11
};
//tbh we should precompile the d3d shaders.

static void dumpprogram(FILE *c, const char *progname)
{
	FILE *s;
	char line[1024];
	int a;
	printf("%25s: ", progname);
	for (a = 0; a < sizeof(shadertype)/sizeof(shadertype[0]); a++)
	{
		sprintf(line, shadertype[a].filepattern, progname);
		if (shadertype[a].apiversion == -1)
			s = fopen(line, "rb");
		else
			s = fopen(line, "rt");
		if (!s)
		{
			printf("%4s", "");
			continue;
		}
		fprintf(c, "#ifdef %s\n", shadertype[a].preprocessor);
		fprintf(c, "{%s, %i, \"%s\",\n", shadertype[a].rendererapi, shadertype[a].apiversion, progname);
		if (shadertype[a].apiversion == -1)
			dumpprogblob(c,s);
		else
			dumpprogstring(c, s);
		fputs("},\n", c);
		fprintf(c, "#endif\n");
		fclose(s);
		fflush(c);

		printf("%4s", shadertype[a].abrv);
	}
	printf("\n");
}

int main(int argc, const char **argv)
{
	FILE *c, *s;
	int i, j, a;

	const char *outname = ((argc>1)?argv[1]:"../gl/r_bishaders.h");

	c = fopen(outname, "wt");

	if (!c)
	{
		printf("unable to open a file\n");
		return 0;
	}

	fprintf(c, "/*\nWARNING: THIS FILE IS GENERATED BY '"__FILE__"'.\nYOU SHOULD NOT EDIT THIS FILE BY HAND\n*/\n\n");

	if (argc>2)
	{	//if we're passed a file list on the commandline then just use that (generally for plugins).
		for (i = 2; i < argc; i++)
			dumpprogram(c, argv[i]);
	}
	else
	{	//use our built in list.
		for (i = 0; *shaders[i]; i++)
			dumpprogram(c, shaders[i]);
	}

	fclose(c);

	return 0;
}
