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. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to