Welcome to mirror list, hosted at ThFree Co, Russian Federation.

BPX_packed_layout.h « ptex « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 082a4c5e474be3cd1caeb1e4eac63a07d6f34571 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#ifndef __BPX_PACKED_LAYOUT_H__
#define __BPX_PACKED_LAYOUT_H__

#include <algorithm>
#include <cassert>
#include <vector>

#include "BPX_rect.h"

// TODO(nicholasbishop): there's a lot of room for improvement
// here. None of this data is saved to a file, so we should be able to
// safely improve it to improve performance, decrease memory usage,
// and fix filtering issues (e.g. by adding mipmaps).
//
// TODO(nicholasbishop): one paper to look at is "A Space-efficient
// and Hardware-friendly Implementation of Ptex".
//
// TODO(nicholasbishop): not sure if it's worth aiming for
// power-of-two output texture?
struct BPXPackedLayout {
	struct Item {
		Item(const int u_res, const int v_res)
			: u_res(u_res), v_res(v_res), id(-1), x(-1), y(-1)
		{}

		int u_res;
		int v_res;

		int id;
		int x;
		int y;
	};

	typedef std::vector<Item> Items;

	BPXPackedLayout(const int count)
		: width(0), height(0), u_max_res(0), v_max_res(0)
	{
		items.reserve(count);
	}

	void add_item(const Item &item)
	{
		items.push_back(item);
		items.back().id = items.size() - 1;
		u_max_res = std::max(u_max_res, item.u_res);
		v_max_res = std::max(v_max_res, item.v_res);
	}

	void finalize()
	{
		if (u_max_res == 0 || v_max_res == 0) {
			return;
		}

		// Sort items descending by v-res
		std::sort(items.begin(), items.end(), sort_res);

		// Decide on output width, TODO(nicholasbishop): extremely
		// arbitrary for now
		width = std::max(u_max_res + 2 * border, 4096);

		// For now only packing mipmap level zero

		// Calc layout
		height = 0;
		int dst_x = 0;
		int dst_y = 0;
		int yinc = 0;
		int max_width = 0;
		for (Items::iterator iter = items.begin();
			 iter != items.end(); ++iter) {
			Item &item = *iter;

			// Check if enough room on this row
			if (dst_x + item.u_res + 2 * border > width) {
				// Move to next row
				assert(yinc != 0);
				dst_y += yinc;
				yinc = 0;
				dst_x = 0;
			}

			// Write final position
			item.x = dst_x + border;
			item.y = dst_y + border;

			dst_x += item.u_res + (2 * border);
			height = std::max(height, dst_y + item.v_res + (2 * border));
			max_width = std::max(dst_x, max_width);

			yinc = std::max(yinc, item.v_res + (2 * border));
		}

		// TODO?
		width = max_width;

		std::sort(items.begin(), items.end(), sort_id);
	}

	const Items &get_items() const
	{
		return items;
	}

	const int get_width() const
	{
		return width;
	}

	const int get_height() const
	{
		return height;
	}

	// Width of filter border (in texels) around each packed face
	static const int border = 1;

private:
	static bool sort_id(const Item &a, const Item &b)
	{
		return a.id < b.id;
	}

	// Order *descending* by v_res, then u_res
	static bool sort_res(const Item &a, const Item &b)
	{
		if (a.v_res == b.v_res) {
			return a.u_res > b.u_res;
		}
		else {
			return a.v_res > b.v_res;
		}
	}

	Items items;

	int width;
	int height;

	int u_max_res;
	int v_max_res;
};

#endif