[Bf-blender-cvs] [4cc26f4] cycles-ptex-24: WIP Ptex texture packing

Nicholas Bishop noreply at git.blender.org
Fri Jan 30 18:00:20 CET 2015


Commit: 4cc26f4fbe3e6b2f45d6deaf6e567f685abf6b9a
Author: Nicholas Bishop
Date:   Fri Jan 16 12:27:41 2015 +0100
Branches: cycles-ptex-24
https://developer.blender.org/rB4cc26f4fbe3e6b2f45d6deaf6e567f685abf6b9a

WIP Ptex texture packing

===================================================================

M	extern/ptex/CMakeLists.txt
A	extern/ptex/bl_ptex.h
A	extern/ptex/pack.cpp
A	extern/ptex/ptex_packed_layout.h

===================================================================

diff --git a/extern/ptex/CMakeLists.txt b/extern/ptex/CMakeLists.txt
index 7e7bcd0..0eda505 100644
--- a/extern/ptex/CMakeLists.txt
+++ b/extern/ptex/CMakeLists.txt
@@ -24,12 +24,16 @@
 # ***** END GPL LICENSE BLOCK *****
 
 set(INC
+	.
 )
 
 set(INC_SYS
 )
 
 set(SRC
+	bl_ptex.h
+	pack.cpp
+
 	src/ptex/PtexCache.h
 	src/ptex/PtexDict.h
 	src/ptex/PtexHalf.h
diff --git a/extern/ptex/bl_ptex.h b/extern/ptex/bl_ptex.h
new file mode 100644
index 0000000..fbfc32c
--- /dev/null
+++ b/extern/ptex/bl_ptex.h
@@ -0,0 +1,74 @@
+#ifndef __BL_PTEX_H__
+#define __BL_PTEX_H__
+
+#ifdef __cplusplus
+/* Silence warning */
+#	define NEW_API 0
+
+#	include "src/ptex/Ptexture.h"
+
+class PtexCache;
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PtexPackedTexture;
+struct PtexCacheHandle;
+
+struct PtexTableElement {
+	int co[2];
+	int res[2];
+};
+
+struct PtexPackedLayout;
+struct PtexPackedLayout *ptex_packed_layout_new(int count);
+void ptex_packed_layout_add(struct PtexPackedLayout *layout,
+							int u_res, int v_res, int id);
+void ptex_packed_layout_finalize(struct PtexPackedLayout *layout);
+void ptex_packed_layout_delete(struct PtexPackedLayout *layout);
+
+struct PtexCacheHandle *ptex_cache_new(void);
+void ptex_cache_delete(struct PtexCacheHandle *ptex_cache_handle);
+
+struct PtexPackedTexture *ptex_packed_texture_new(void);
+
+void ptex_packed_texture_delete(struct PtexPackedTexture *ppt);
+
+bool ptex_packed_texture_fill(struct PtexPackedTexture *output,
+							  const char *path,
+							  const int width,
+							  struct PtexCacheHandle *ptex_cache_handle);
+
+typedef void (*LoopDataFunc)(void *src, int index, void **texels,
+							 int *u_rlog2, int *v_rlog2);
+
+bool ptex_packed_texture_from_layout(struct PtexPackedTexture *output,
+									 struct PtexPackedLayout *layout,
+									 LoopDataFunc loop_data,
+									 void *loop_data_src,
+									 const int num_loops,
+									 // TODO, should use an enum for
+									 // data_type
+									 const int data_type,
+									 const int num_channels,
+									 const int alpha_channel);
+
+int ptex_packed_texture_width(const struct PtexPackedTexture *ppt);
+int ptex_packed_texture_height(const struct PtexPackedTexture *ppt);
+int ptex_packed_texture_bytes_per_texel(const struct PtexPackedTexture *ppt);
+int ptex_packed_texture_num_channels(const struct PtexPackedTexture *ppt);
+const void *ptex_packed_texture_texels(const struct PtexPackedTexture *ppt);
+int ptex_packed_texture_table_len(const struct PtexPackedTexture *ppt);
+
+const struct PtexTableElement *
+ptex_packed_texture_table_elem(const struct PtexPackedTexture *ppt,
+							   const int index);
+
+#ifdef __cplusplus
+}  /* extern "C" */
+#endif
+
+#endif
diff --git a/extern/ptex/pack.cpp b/extern/ptex/pack.cpp
new file mode 100644
index 0000000..2b9a8dd
--- /dev/null
+++ b/extern/ptex/pack.cpp
@@ -0,0 +1,795 @@
+#include "ptex_packed_layout.h"
+
+
+#include <OpenImageIO/imageio.h>
+OIIO_NAMESPACE_USING
+
+#include <cassert>
+#include <vector>
+
+#include "bl_ptex.h"
+
+// TODO, silly to copy utility classes...
+struct float2 {
+	float x, y;
+
+	void operator+=(const float2 &other)
+	{
+		x += other.x;
+		y += other.y;
+	}
+
+	float2 operator*(const float s) const
+	{
+		float2 result = {x * s, y * s};
+		return result;
+	}
+};
+
+static float2 make_float2(float x, float y)
+{
+	float2 f = {x, y};
+	return f;
+}
+
+// TODO, obviously not correct
+typedef unsigned int uint;
+typedef unsigned char uint8_t;
+
+PtexPackedLayout *ptex_packed_layout_new(const int count)
+{
+	return new PtexPackedLayout(count);
+}
+
+void ptex_packed_layout_add(PtexPackedLayout * const layout,
+							const int u_res, const int v_res,
+							const int id)
+{
+	layout->add_item(PtexPackedLayout::Item(u_res, v_res, id));
+}
+
+void ptex_packed_layout_finalize(PtexPackedLayout * const layout)
+{
+	layout->finalize();
+}
+
+void ptex_packed_layout_delete(PtexPackedLayout *layout)
+{
+	delete layout;
+}
+
+struct PtexPackedTexture {
+	PtexPackedTexture() : width(0), height(0) {}
+
+	class Cursor {
+	public:
+		Cursor(PtexPackedTexture &output, const int start_x,
+			   const int start_y)
+		: output(output),
+		  offset(output.calc_offset(start_x, start_y))
+		{
+		}
+
+		void set_increment(const int new_incr)
+		{
+			incr = new_incr;
+		}
+
+		void step()
+		{
+			offset += incr;
+		}
+
+		uint8_t *data() {
+			return output.data(offset);
+		}
+
+	private:
+		PtexPackedTexture &output;
+		int incr;
+		int offset;
+	};
+
+	int calc_offset(const int x, const int y) const
+	{
+		return (y * width + x) * bytes_per_texel;
+	}
+
+	uint8_t *data(const int pixel_index)
+	{
+		assert(pixel_index >= 0);
+		assert(pixel_index < texels.size() - num_channels);
+
+		return texels.data() + pixel_index;
+	}
+
+	void set_texel_type(const int channels, const Ptex::DataType dt)
+	{
+		num_channels = channels;
+		data_type = dt;
+		bytes_per_texel = channels * Ptex::DataSize(dt);
+	}
+
+	void resize(const int w, const int h)
+	{
+		width = w;
+		height = h;
+
+		dst_stride = width * bytes_per_texel;
+	
+		texels.resize(width * height * bytes_per_texel);
+	}
+
+	// TODO: more privacy here
+
+	std::vector<uint8_t> texels;
+
+	std::vector<PtexTableElement> table;
+
+	uint width;
+	uint height;
+
+	int num_channels;
+
+	int bytes_per_texel;
+	int dst_stride;
+
+	void test_write() {
+		// Quick test to visually examine the packed output
+		const char *filename = "/tmp/packed.png";
+		ImageOutput *out = ImageOutput::create(filename);
+		if (out) {
+			ImageSpec spec(width, height, num_channels, TypeDesc::UINT8);
+			out->open(filename, spec);
+			out->write_image(TypeDesc::UINT8, texels.data());
+			std::cout << "ptex test written: " << filename << std::endl;
+			out->close();
+		}
+	}
+
+	Ptex::DataType data_type;
+};
+
+struct PtexEdgeIter {
+	/* Set up a texel iterator for one edge of a face
+	 *
+	 * face and edge_id: specify the edge being iterated over
+	 *
+	 * from_res: the resolution of a neighboring face, controls the
+	 *           distance to step each time next() is called; next()
+	 *           can be called up to `from_res` times.
+	 *
+	 * reverse: iterate over the edge backwards. In general this is
+	 *          `true` because adjacent face edges have (implicit)
+	 *          opposite directions.
+	 */
+	PtexEdgeIter(PtexFaceData &face,
+				 const Ptex::EdgeId edge_id,
+				 const int from_res,
+				 const bool reverse)
+		: face(face)
+	{
+		const Ptex::Res &res = face.res();
+
+		float u_res = res.u() - 1.0f;
+		float v_res = res.v() - 1.0f;
+		const float u_incr = (u_res + 1.0f) / (float)from_res;
+		const float v_incr = (v_res + 1.0f) / (float)from_res;
+
+		switch (edge_id) {
+			case Ptex::e_bottom:
+				if (reverse) {
+					pos = make_float2(u_res, 0);
+					incr = make_float2(-u_incr, 0);
+				}
+				else {
+					pos = make_float2(0, 0);
+					incr = make_float2(u_incr, 0);
+				}
+				break;
+
+			case Ptex::e_right:
+				if (reverse) {
+					pos = make_float2(u_res, v_res);
+					incr = make_float2(0, -v_incr);
+				}
+				else {
+					pos = make_float2(u_res, 0);
+					incr = make_float2(0, v_incr);
+				}
+				break;
+
+			case Ptex::e_top:
+				if (reverse) {
+					pos = make_float2(0, v_res);
+					incr = make_float2(u_incr, 0);
+				}
+				else {
+					pos = make_float2(u_res, v_res);
+					incr = make_float2(-u_incr, 0);
+				}
+				break;
+
+			case Ptex::e_left:
+				if (reverse) {
+					pos = make_float2(0, 0);
+					incr = make_float2(0, v_incr);
+				}
+				else {
+					pos = make_float2(0, v_res);
+					incr = make_float2(0, -v_incr);
+				}
+		}
+	}
+
+	void step() {
+		pos += incr;
+	}
+
+	void step(int n) {
+		pos += incr * n;
+	}
+
+	void copy_num_texels(PtexPackedTexture::Cursor &cursor,
+						 const int num)
+	{
+		for (int i = 0; i < num; i++) {
+			copy_texel(cursor.data());
+			cursor.step();
+			step();
+		}
+	}
+
+	/* TODO(nicholasbishop): not doing any special filtering for
+	 * adjacent faces of differing resolutions, not sure how much that
+	 * will matter in practice */
+	void copy_texel(void *texel)
+	{
+		const int x = (int)(pos.x);
+		const int y = (int)(pos.y);
+		assert(x < face.res().u());
+		assert(y < face.res().v());
+		face.getPixel(x, y, texel);
+	}
+
+	PtexFaceData &face;
+	float2 pos;
+	float2 incr;
+};
+
+// TODO(nicholasbishop): this isn't necessarily the nicest or most
+// efficient way to go about this, easiest for now though since the
+// packing code is implemented on top of the Ptex API
+//
+// TODO(nicholasbishop): also now that I've written it looks gross.
+class BlenderPtexTexture : public PtexTexture {
+private:
+	class FaceData : public PtexFaceData {
+	public:
+		void *texels;
+		Ptex::Res cres;
+		int bytes_per_texel;
+
+		virtual void release()
+		{}
+
+		virtual bool isConstant()
+		{
+			return false;
+		}
+
+		virtual Ptex::Res res()
+		{
+			return cres;
+		}
+
+		virtual void getPixel(int u, int v, void *result)
+		{
+			if (texels) {
+				memcpy(result,
+					   (char*)texels + (v * cres.u() + u) * bytes_per_texel,
+					   bytes_per_texel);
+			}
+		}
+
+		virtual void *getData()
+		{
+			return texels;
+		}
+
+		virtual bool isTiled()
+		{
+			return false;
+		}
+
+		virtual Ptex::Res tileRes()
+		{
+			assert(!"tileRes not implemented");
+		}
+
+		virtual PtexFaceData *getTile(int tile)
+		{
+			assert(!"getTile not implemented");
+		}
+	};
+
+public:
+	BlenderPtexTexture(const LoopDataFunc loop_data,
+					   void *loop_data_src,
+					   const int num_loops,
+					   const Ptex::DataType data_type,
+					   const int num_channels,
+					   const int alpha_channel)
+		: num_loops(num_loops),
+		  data_type(data_type),
+		  num_channels(num_channels),
+		  alpha_channel(alpha_channel),
+		  bytes_per_texel(num_channels * Ptex::DataSize(data_type))
+	{
+		face_info.reserve(num_loops);
+		face_data.reserve(num_loops);
+		for (int i = 0; i < num_loops; i++) {
+			FaceData fd;
+			int ulog2 = 0, vlog2 = 0;
+			loop_data(loop_data_src, i, &fd.texels, &ulog2, &vlog2);
+			Ptex::Res res(ulog2, vlog2);
+			fd.cres = res;
+			fd.bytes_per_texel = bytes_per_texel;
+			
+			// Adjacency TODO
+			face_info.push_back(res);
+			face_data.push_back(fd);
+		}
+	}
+
+	virtual void release

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list