Browse Source

Some work for color grading

Panagiotis Christopoulos Charitos 10 years ago
parent
commit
e15641a728
4 changed files with 202 additions and 4 deletions
  1. 2 0
      include/anki/renderer/Pps.h
  2. 16 0
      src/renderer/Pps.cpp
  3. 20 4
      tools/texture/convert_image.py
  4. 164 0
      tools/texture/segment_image.py

+ 2 - 0
include/anki/renderer/Pps.h

@@ -75,6 +75,8 @@ public:
 		return m_sslr;
 		return m_sslr;
 	}
 	}
 
 
+	Error loadColorGradingTexture(CString filename);
+
 	/// @privatesection
 	/// @privatesection
 	/// @{
 	/// @{
 	const TextureHandle& _getRt() const
 	const TextureHandle& _getRt() const

+ 16 - 0
src/renderer/Pps.cpp

@@ -9,6 +9,7 @@
 #include "anki/renderer/Ssao.h"
 #include "anki/renderer/Ssao.h"
 #include "anki/util/Logger.h"
 #include "anki/util/Logger.h"
 #include "anki/misc/ConfigSet.h"
 #include "anki/misc/ConfigSet.h"
+#include "anki/resource/ImageLoader.h"
 
 
 namespace anki {
 namespace anki {
 
 
@@ -81,6 +82,9 @@ Error Pps::initInternal(const ConfigSet& config)
 
 
 	ANKI_CHECK(m_r->createDrawQuadPipeline(m_frag->getGrShader(), m_ppline));
 	ANKI_CHECK(m_r->createDrawQuadPipeline(m_frag->getGrShader(), m_ppline));
 
 
+	// LUT
+	ANKI_CHECK(loadColorGradingTexture("engine_data/default_lut.ankitex"));
+
 	cmdBuff.finish();
 	cmdBuff.finish();
 
 
 	return ErrorCode::NONE;
 	return ErrorCode::NONE;
@@ -97,6 +101,18 @@ Error Pps::init(const ConfigSet& config)
 
 
 	return err;
 	return err;
 }
 }
+//==============================================================================
+Error Pps::loadColorGradingTexture(CString filename)
+{
+	/*StringAuto lutFname(getAllocator());
+	m_r->_getResourceManager().fixResourceFilename(
+		"engine_data/default_lut.ankitex", lutFname);
+
+	ImageLoader loader(getAllocator());
+	ANKI_CHECK(loader.load(lutFname.toCString(), MAX_U32, true));*/
+
+	return ErrorCode::NONE;
+}
 
 
 //==============================================================================
 //==============================================================================
 Error Pps::run(CommandBufferHandle& cmdBuff)
 Error Pps::run(CommandBufferHandle& cmdBuff)

+ 20 - 4
tools/texture/ankitexture.py → tools/texture/convert_image.py

@@ -12,7 +12,6 @@ import shutil
 #
 #
 # Config
 # Config
 #
 #
-
 class Config:
 class Config:
 	in_files = []
 	in_files = []
 	out_file = ""
 	out_file = ""
@@ -48,6 +47,11 @@ DC_RAW = 1 << 0
 DC_ETC2 = 1 << 1
 DC_ETC2 = 1 << 1
 DC_S3TC = 1 << 2
 DC_S3TC = 1 << 2
 
 
+# Texture filtering
+TF_DEFAULT = 0
+TF_LINEAR = 1
+TF_NEAREST = 2
+
 #
 #
 # DDS
 # DDS
 #
 #
@@ -128,7 +132,6 @@ class DdsHeader:
 #
 #
 # ETC2
 # ETC2
 #
 #
-	
 class PkmHeader:
 class PkmHeader:
 	""" The header of a pkm file """
 	""" The header of a pkm file """
 	
 	
@@ -157,7 +160,6 @@ class PkmHeader:
 #
 #
 # Functions
 # Functions
 # 
 # 
-
 def printi(s):
 def printi(s):
 	print("[I] %s" % s)
 	print("[I] %s" % s)
 
 
@@ -220,6 +222,10 @@ def parse_commandline():
 			help = "assume the input textures are sRGB. If this option is " \
 			help = "assume the input textures are sRGB. If this option is " \
 			"true then convert them to linear RGB")
 			"true then convert them to linear RGB")
 
 
+	parser.add_option("--filter", dest = "filter", type = "string",
+			default = "default", help = "texture filtering. Can be: " \
+			"default, linear, nearest")
+
 	# Add the default value on each option when printing help
 	# Add the default value on each option when printing help
 	for option in parser.option_list:
 	for option in parser.option_list:
 		if option.default != ("NO", "DEFAULT"):
 		if option.default != ("NO", "DEFAULT"):
@@ -241,6 +247,15 @@ def parse_commandline():
 	else:
 	else:
 		parser.error("Unrecognized type: " + options.type)
 		parser.error("Unrecognized type: " + options.type)
 
 
+	if options.filter == "default":
+		filter = TF_DEFAULT
+	elif options.filter == "linear":
+		filter = TF_LINEAR
+	elif options.filter == "nearest":
+		filter = TF_NEAREST
+	else:
+		parser.error("Unrecognized type: " + options.filter)
+
 	config = Config()
 	config = Config()
 	config.in_files = options.inp.split(":")
 	config.in_files = options.inp.split(":")
 	config.out_file = options.out
 	config.out_file = options.out
@@ -251,6 +266,7 @@ def parse_commandline():
 	config.no_alpha = options.no_alpha
 	config.no_alpha = options.no_alpha
 	config.no_uncompressed = options.no_uncompressed
 	config.no_uncompressed = options.no_uncompressed
 	config.to_linear_rgb = options.to_linear_rgb
 	config.to_linear_rgb = options.to_linear_rgb
+	config.filter = filter
 
 
 	return config
 	return config
 
 
@@ -580,7 +596,7 @@ def convert(config):
 		raise Exception("RGBA image and normal does not make much sense")
 		raise Exception("RGBA image and normal does not make much sense")
 
 
 	for i in range(1, len(config.in_files)):
 	for i in range(1, len(config.in_files)):
-		(color_format_2, width_2, height_2) = identify_image(in_files[i])
+		(color_format_2, width_2, height_2) = identify_image(config.in_files[i])
 
 
 		if width != width_2 or height != height_2 \
 		if width != width_2 or height != height_2 \
 				or color_format != color_format_2:
 				or color_format != color_format_2:

+ 164 - 0
tools/texture/segment_image.py

@@ -0,0 +1,164 @@
+#!/usr/bin/python3
+
+import optparse
+import sys
+import struct
+
+class Config:
+	in_file = ""
+	out_dir = ""
+
+def printi(s):
+	print("[I] %s" % s)
+
+def parse_commandline():
+	""" Parse the command line arguments """
+
+	parser = optparse.OptionParser(usage = "usage: %prog [options]", \
+			description = "This program takes a single 2D image and spits "\
+			"a number of images. Input and output images should be TGA.")
+
+	parser.add_option("-i", "--input", dest = "inp",
+			type = "string", help = "specify the image to split.")
+
+	parser.add_option("-o", "--output", dest = "out",
+			type = "string", help = "the directory of the output images.")
+
+	parser.add_option("-s", "--size", dest = "size",
+			type = "string", metavar="WxH",
+			help = "size of the splits.")
+
+	# Add the default value on each option when printing help
+	for option in parser.option_list:
+		if option.default != ("NO", "DEFAULT"):
+			option.help += (" " if option.help else "") + "[default: %default]"
+
+	(options, args) = parser.parse_args()
+
+	if not options.inp or not options.out or not options.size:
+		parser.error("argument is missing")
+
+	# Parse the --size
+	size = [0, 0]
+	try:
+		size_strs = options.size.split("x")
+		size[0] = int(size_strs[0])
+		size[1] = int(size_strs[1])
+	except:
+		parser.error("incorrect --size: %s" % sys.exc_info()[0])
+
+	config = Config()
+	config.in_file = options.inp
+	config.out_dir = options.out
+	config.size = size
+
+	return config
+
+def split(filename, split_size, out_dir):
+	""" Load an image """
+
+	# Read and check the header
+	uncompressed_tga_header = struct.pack("BBBBBBBBBBBB", \
+			0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+
+	in_file = open(filename, "rb")
+	tga_header = in_file.read(12)
+
+	if len(tga_header) != 12:
+		raise Exception("Failed reading TGA header")
+	
+	if uncompressed_tga_header != tga_header:
+		raise Exception("Incorrect TGA header")
+
+	# Read the size and bpp
+	header6_buff = in_file.read(6)
+
+	if len(header6_buff) != 6:
+		raise Exception("Failed reading TGA header #2")
+		
+	header6 = struct.unpack("BBBBBB", header6_buff)
+
+	img_width = header6[1] * 256 + header6[0]
+	img_height = header6[3] * 256 + header6[2]
+	img_bpp = header6[4];
+
+	if img_bpp != 24 and img_bpp != 32:
+		raise Exception("Unexpected bpp")
+
+	# Check split size against the image
+	if (img_width % split_size[0]) != 0 or (img_height % split_size[1]) != 0:
+		raise Exception("Sizes of the input image and the split are not " \
+				"compatible: %d %d vs %d %d" 
+				% (img_width, img_height, split_size[0], split_size[1]))
+
+	# Dump the data to an array
+	pixels = []
+	for y in range(0, img_height):
+		pixels.append([])
+		for x in range(0, img_width):
+			pixels[y].append([])
+
+			if img_bpp == 24:
+				pixel = in_file.read(3)
+				
+				pixels[y][x].append(pixel[0])
+				pixels[y][x].append(pixel[1])
+				pixels[y][x].append(pixel[2])
+			else:
+				pixel = in_file.read(4)
+				
+				pixels[y][x].append(pixel[0])
+				pixels[y][x].append(pixel[1])
+				pixels[y][x].append(pixel[2])
+				pixels[y][x].append(pixel[3])
+
+	# Iterate splits and write them
+	split_count_x = int(img_width / split_size[0])
+	split_count_y = int(img_height / split_size[1])
+
+	count = 0
+	for y in range(0, split_count_y):
+		for x in range(0, split_count_x):
+
+			# Open file and write header
+			out_file = open("%s/out_%02d.tga" % (out_dir, count), "wb")
+			
+			out_file.write(uncompressed_tga_header)
+
+			header2 = struct.pack("BBBBBB", split_size[0] % 256, 
+					int(split_size[0] / 256), split_size[1] % 256, 
+					int(split_size[1] / 256), img_bpp, 0)
+
+			out_file.write(header2)
+
+			# Iterate split pixels
+			for sy in range(0, split_size[1]):
+				for sx in range(0, split_size[0]):
+
+					in_x = x * split_size[0] + sx
+					in_y = y * split_size[1] + sy
+
+					if(img_bpp == 24):
+						pixels_s = struct.pack("BBB", pixels[in_y][in_x][0],
+								pixels[in_y][in_x][1], pixels[in_y][in_x][2])
+					else:
+						pixels_s = struct.pack("BBBB", pixels[in_y][in_x][0], 
+								pixels[in_x][in_y][1], pixels[in_y][in_x][2],
+								pixels[in_y][in_x][3])
+
+					out_file.write(pixels_s)
+
+			out_file.close()
+			count += 1
+
+def main():
+	""" The main """
+
+	config = parse_commandline();
+	
+	split(config.in_file, config.size, config.out_dir)
+
+	printi("Done!")
+
+if __name__ == "__main__":
+	main()