[Bf-blender-cvs] [2ece5a7] cycles-ptex-06: Move ptex packing stuff out of cycles
Nicholas Bishop
noreply at git.blender.org
Fri Jan 16 12:54:39 CET 2015
Commit: 2ece5a7770eae5a1aa861334a5f0803907d96a4d
Author: Nicholas Bishop
Date: Fri Jan 16 12:54:00 2015 +0100
Branches: cycles-ptex-06
https://developer.blender.org/rB2ece5a7770eae5a1aa861334a5f0803907d96a4d
Move ptex packing stuff out of cycles
===================================================================
M extern/ptex/CMakeLists.txt
M extern/ptex/bl_ptex.h
A extern/ptex/pack.cpp
M intern/cycles/CMakeLists.txt
M intern/cycles/render/image.cpp
===================================================================
diff --git a/extern/ptex/CMakeLists.txt b/extern/ptex/CMakeLists.txt
index 47da6cc..0eda505 100644
--- a/extern/ptex/CMakeLists.txt
+++ b/extern/ptex/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC_SYS
set(SRC
bl_ptex.h
+ pack.cpp
src/ptex/PtexCache.h
src/ptex/PtexDict.h
diff --git a/extern/ptex/bl_ptex.h b/extern/ptex/bl_ptex.h
index 4e4668a..94ae953 100644
--- a/extern/ptex/bl_ptex.h
+++ b/extern/ptex/bl_ptex.h
@@ -6,4 +6,31 @@
#include "src/ptex/Ptexture.h"
+struct PtexPackedTexture;
+class PtexCache;
+
+struct PtexTableElement {
+ uint co[2];
+ uint res[2];
+};
+
+struct PtexPackedTexture *ptex_packed_texture_new();
+
+void ptex_packed_texture_delete(struct PtexPackedTexture *ppt);
+
+bool ptex_packed_texture_fill(struct PtexPackedTexture *output,
+ const char *path,
+ const int width,
+ class PtexCache *ptex_cache);
+
+int ptex_packed_texture_width(const struct PtexPackedTexture *ppt);
+int ptex_packed_texture_height(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);
+
#endif
diff --git a/extern/ptex/pack.cpp b/extern/ptex/pack.cpp
new file mode 100644
index 0000000..d708838
--- /dev/null
+++ b/extern/ptex/pack.cpp
@@ -0,0 +1,538 @@
+#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;
+
+using std::vector;
+
+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;
+ }
+
+ // TODO: more privacy here
+
+ vector<uint8_t> texels;
+
+ 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();
+ }
+ }
+};
+
+static int ptex_data_type_size_in_bytes(const Ptex::DataType dt)
+{
+ switch (dt) {
+ case Ptex::dt_uint8:
+ return 1;
+ case Ptex::dt_uint16:
+ return 2;
+ case Ptex::dt_half:
+ return 2;
+ case Ptex::dt_float:
+ return 4;
+ }
+
+ // Error
+ return 0;
+}
+
+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;
+};
+
+static void ptex_average_corner(PtexPtr<PtexTexture> &r,
+ const int start_face_id,
+ Ptex::EdgeId edge_id,
+ void *output)
+{
+ const Ptex::DataType data_type = r->dataType();
+ const int num_channels = r->numChannels();
+ assert(num_channels <= 4);
+
+ /* TODO: handle more than four channels */
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+
+ /* TODO: probably special cases to handle at mesh boundaries?
+ * Might need to traverse edges in both directions */
+
+ /* TODO: subface corners */
+
+ int face_id = start_face_id;
+ int num_adj = 0;
+ do {
+ float ftexel[4];
+ char texel[sizeof(float) * 4];
+
+ PtexFaceData &data = *r->getData(face_id);
+ const Ptex::FaceInfo &info = r->getFaceInfo(face_id);
+ const Ptex::Res res = data.res();
+ const int u_res = res.u() - 1;
+ const int v_res = res.v() - 1;
+ switch (edge_id) {
+ case Ptex::e_bottom:
+ data.getPixel(0, 0, texel);
+ break;
+ case Ptex::e_right:
+ data.getPixel(u_res, 0, texel);
+ break;
+ case Ptex::e_top:
+ data.getPixel(u_res, v_res, texel);
+ break;
+ case Ptex::e_left:
+ data.getPixel(0, v_res, texel);
+ break;
+ }
+
+ Ptex::ConvertToFloat(ftexel, texel, data_type, num_channels);
+ for (int i = 0; i < 4; i++) {
+ accum[i] += ftexel[i];
+ }
+ num_adj++;
+
+ if (num_adj > 10) {
+ // TODO, code is not yet correct so prevent infinite loops
+ break;
+ }
+
+ /* Move to next face and edge */
+ face_id = info.adjface(edge_id);
+ edge_id = (Ptex::EdgeId)(((int)info.adjedge(edge_id) + 1) % 4);
+
+ } while (face_id != start_face_id && face_id != -1);
+
+ /* Average */
+ const float fac = 1.0f / (float)num_adj;
+ for (int i = 0; i < 4; i++) {
+ accum[i] *= fac;
+ }
+
+ /* Output */
+ Ptex::ConvertFromFloat(output, accum, data_type, num_channels);
+
+}
+
+static void ptex_copy_face_border(PtexPackedTexture::Cursor &cursor,
+ PtexPtr<PtexTexture> &r,
+ const int face_id,
+ const Ptex::FaceInfo &info,
+ const Ptex::EdgeId edge_id,
+ const int side_res)
+{
+ ptex_average_corner(r, face_id, edge_id, cursor.data());
+ cursor.step();
+
+ /* In general there is only one adjacent face, but when a quad is
+ * adjacent to a non-quad there are two adjacent subfaces */
+ int adj_face_id[2] = {info.adjface(edge_id), -1};
+ Ptex::EdgeId adj_edge[2] = {info.adjedge(edge_id)};
+
+ if (adj_face_id[0] == -1) {
+ /* If there's no adjacent face, pretend the face is adjacent
+ * to itself (i.e. copy its own borders) */
+ PtexEdgeIter iter(*r->getData(face_id), edge_id, side_res, false);
+ iter.copy_num_texels(cursor, side_res);
+ }
+ else {
+ const Ptex::FaceInfo &adj_info = r->getFaceInfo(adj_face_id[0]);
+ const bool is_subface = info.isSubface();
+ if (!is_subface && adj_info.isSubface()) {
+ /* Face is adjacent to two subfaces */
+ int next_edge_id = (adj_edge[0] + 3) % 4;
+ adj_face_id[1] = adj_info.adjface(next_edge_id);
+ adj_edge[1] = adj_info.adjedge(next_edge_id);
+ adj_edge[1] = (Ptex::EdgeId)((adj_edge[1] + 3) % 4);
+ }
+
+ PtexFaceData *face_data[2] = {
+ r->getData(adj_face_id[0]),
+ adj_face_id[1] == -1 ? NULL : r->getData(adj_face_id[1])
+ };
+
+ if (is_subface && !adj_info.isSubface()) {
+ PtexEdgeIter iter(*face_data[0], adj_edge[0], side_res * 2, true);
+ const bool is_primary = adj_info.adjface(adj_edge[0]) == face_id;
+ if (is_primary) {
+ iter.step(side_res);
+ }
+
+ iter.copy_num_texels(cursor, side_res);
+ }
+ else if (!is_subface && adj_info.isSubface()) {
+ const int half_side_res = side_res / 2;
+ for (int sf = 0; sf <= 1; sf++) {
+ PtexEdgeIter iter(*face_data[sf], adj_edge[sf],
+ half_side_res, true);
+ iter.copy_num_texels(cursor, half_side_res);
+ }
+ }
+ else {
+ PtexEdgeIter iter(*face_data[0], adj_edge[0], side_res, true);
+ iter.copy_num_texels(cursor, side_res);
+ }
+ }
+}
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list