Also, I forgot to mention, I'm now the proud owner of https://crates.io/crates/openimageio (among several other crates such as OpenVDB, OpenColorIO, etc). I'd like to hand it off to the project owners of the libraries they represent (such as the OIIO project, ASWF, etc). The other crates are another story (I'll send a message on the ASWF community forum), but I'd like to hand the OIIO crate off to this project. Larry, if you want to take ownership of it, then it's all yours. I can also keep some level of joint ownership of the crate if you want as well. I'm open to anything.
On Mon, Oct 19, 2020 at 7:31 PM Scott Wilson <[email protected]> wrote: > I've taken a look at a few C libraries, and here's my initial results: > > Git: (Example from commit.h) > GIT_EXTERN(const git_oid *) git_commit_id(const git_commit *commit); > > Tensorflow: > https://github.com/tensorflow/tensorflow/blob/master/tensorflow/c/c_api.h > > SDL: > https://github.com/SDL-mirror/SDL/blob/master/include/SDL_vulkan.h > > - Prefix is still important > - It looks like the struct is prefixed, and the methods for the struct are > prefixed with the struct. So, there may be a struct called git_repository, > and the method would be called something like git_repository_open. For the > most part, it looks like structs would be named something like > OIIO_ImageBuf vs OIIOImageBuf. I personally don't like the _ in > class/struct names, but I come from Python. > - There doesn't seem to be a consensus on constructor/destructor naming. > I'm guessing we may want to go for Type_init and Type_free? Or there's the > Rust way Type_new and Type_drop. > - If we want to borrow some conventions from Rust: > https://rust-lang.github.io/api-guidelines/naming.html For example, a > constructor is usually called Type::new(some_args: Arg) -> Type, or > Type::with_something(something: Something) -> Type. > > On Mon, Oct 19, 2020 at 5:53 PM Larry Gritz <[email protected]> wrote: > >> As much as I'd like things as short as possible, I'd prefer names and >> capitalization have as much symmetry as possible between the C++ and C >> interfaces. For users trying to make sense of the APIs, we want to honor >> the "principle of least surprise." >> >> But I'd certainly defer to modern C sensibilities, however they have >> evolved their practices without true namespaces and classes. >> >> >> >> On Oct 19, 2020, at 5:23 PM, Scott Wilson <[email protected]> wrote: >> >> Yeah, I think we'd want to target C99, because as far as I know, most >> things with a C ffi target C99. >> >> I'll try to gather a list of C projects to see how they name things. >> Also, I'll probably share some of how Rust names functions and methods to >> hopefully gather some more options. >> >> On Mon., Oct. 19, 2020, 3:55 p.m. Anders Langlands, < >> [email protected]> wrote: >> >>> I’d personally prefer to see if we could shorten the names a little so >>> “oiio_ii_open” instead of “OIIO_ImageInput_open” if we could make sure that >>> there wouldn’t be any abbreviation conflicts. The long form does have the >>> advantage that it’s unambiguous though. >>> >>> Regarding standards, Visual Studio has only just added support for C11 >>> and C17 in preview and I don’t think we’d need anything beyond C99 for an >>> API wrapper anyway? >>> >>> >>> >>> On Tue, 20 Oct 2020 at 10:18, Larry Gritz <[email protected]> wrote: >>> >>>> I've been in C++ land for so long that I'm afraid I don't know the >>>> idioms that modern C culture likes these days. Is what you describe >>>> OIIO_ImageInput_open or OIIO_ImageBufAlgo_add... does that look like the >>>> way a 2020 C programmer would try to "namespace" things in C that has no >>>> namespaces? Or would a C programmer scoff at how wordy it is? >>>> >>>> As far as how to name overloads... I think it might be instructive to >>>> look at a few individual cases first and what feels right, then see if they >>>> generalize into an overall rule. I'm hesitant to propose a rule first >>>> without examples to know if we're going to hate it in practice. >>>> >>>> Which C standard would you want to target? >>>> >>>> -- lg >>>> >>>> >>>> On Oct 19, 2020, at 1:51 PM, Scott Wilson <[email protected]> >>>> wrote: >>>> >>>> Sounds good to me. Also, if you want to automate the c bindings to some >>>> degree, then you can look at https://github.com/EmbarkStudios/physx-rs >>>> for inspiration. There's a talk in the readme with their c bindings >>>> builder. Failing that, I'm fine with going through the legwork of making >>>> the c interface. >>>> >>>> If I may make a suggestion for the naming, I'd suggest more or less >>>> following what OIIO does in C++. So, for example, >>>> OIIO::ImageInput.open(...) would be OIIO_ImageInput_open(...) and >>>> classes/structs would be OIIOImageInput. >>>> >>>> The only question I have at the moment is how do we want to handle >>>> naming functions with overrides? >>>> >>>> On Mon., Oct. 19, 2020, 1:00 p.m. Anders Langlands, < >>>> [email protected]> wrote: >>>> >>>>> Branching this thread to talk specifics... >>>>> >>>>> So to summarize the different approaches we've each taken, in my repo ( >>>>> https://github.com/anderslanglands/oiio-rs/tree/master/coiio) I have >>>>> a small shim library that creates a C interface to OIIO by wrapping with >>>>> functions like: >>>>> >>>>> ImageBuf ImageBuf_create(const char* filename) { >>>>> return new OIIO::ImageBuf(OIIO::string_view(filename)); >>>>> } >>>>> >>>>> When building the rust crate, this is compiled into a static library >>>>> by Cargo using CMake, with the environment variable OIIO_ROOT specifying >>>>> the path to the OIIO installation. Currently the build script errors out >>>>> if >>>>> OIIO_ROOT is not specified, but it would be trivial to have it default to >>>>> /usr/local etc. I also at one point had it downloading OIIO and building >>>>> it >>>>> directly, but cmake-rs had some issues with always rebuilding OIIO on any >>>>> change to the crate, which made development interminable, so I stripped >>>>> that out. That was nearly two years ago so may have been fixed. A good >>>>> alternative would be to provide a separate (bash or python) build script >>>>> that would download deps and run the build manually as a pre-process. >>>>> >>>>> From what I can tell from Scott's repo, cxx is doing essentially the >>>>> same thing, but cxx handles building the shim library internally, so >>>>> there's no need for invoking CMake from build.rs. Presumably you'd >>>>> still need to specify the path to (and potentially build) OIIO and its >>>>> deps >>>>> using this method. If you compare the code in Scott's repo to mine, you >>>>> can >>>>> see they're very similar indeed. >>>>> >>>>> The issue I see here is that I don't think cxx actually saves you >>>>> anything. In fact there's *more* code in the cxx case because you're >>>>> specifying both the implementation (ffi.cpp) and the interface (ffi.h), >>>>> whereas I only have to specify the implementation (coiio.cpp) and the >>>>> interface is declared solely in ffi.rs. >>>>> >>>>> Building and linking the static library is the easiest part of the >>>>> process, and is also the part that would be more generally useful outside >>>>> of just Rust - you could use that C interface to trivially bind any >>>>> language you want, so I think we want to preserve that. >>>>> >>>>> That leaves the question of how do we generate the C interface in the >>>>> first place. I've been doing it manually, which is a tedious process, but >>>>> works. Since it's just calling the C++ directly I think it's also >>>>> reasonably sturdy against changes to the underlying OIIO API, since the >>>>> compiler should catch most misuses, although I'm sure there are plenty of >>>>> opportunities for subtle bugs still. Not to mention bikeshedding about >>>>> naming conventions and code styles :) >>>>> >>>>> My idea for how to make the binding generation more automatic was to >>>>> try and leverage libclang to generate the C wrappers semi-automatically. >>>>> This would still require a fair amount of code: first writing the binding >>>>> generator, then writing the rules for how to wrap the C++ API, but should >>>>> allow generating the C API automatically, rather than maintaining it >>>>> manually for every release. The downside is obviously this tool doesn't >>>>> exist yet, and it would add a (optional) dependency on clang to the >>>>> project. >>>>> >>>>> I think the best course of action here would be to write a C wrapper >>>>> in OIIO itself that could be maintained along with the rest of the >>>>> project. >>>>> This would build a little C99 library that could be installed alongside >>>>> the >>>>> C++ library. This would unfortunately mean manually writing a header to go >>>>> with it, although that part could probably be automated with a little >>>>> scripting. >>>>> >>>>> Then oiio-rs should be a completely separate Rust crate that just uses >>>>> bindgen to generate the unsafe API from the C library automatically, and >>>>> provides a safe API on top of that. (Larry - Rust/Cargo kinda assumes that >>>>> Cargo is the thing doing all the building and dependency management, so >>>>> trying to provide a Rust artefact from the OIIO build process would be >>>>> painful if it's possible at all). >>>>> >>>>> Let me know what you think. >>>>> >>>>> >>>>> Cheers, >>>>> Anders >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> On Tue, 20 Oct 2020 at 02:53, Alvaro Castaneda <[email protected]> >>>>> wrote: >>>>> >>>>>> Hi Larry and Anders >>>>>> I'm helping Scott with the Rust Wrapper. >>>>>> using CXX is been good, it is a very manual process and makes it only >>>>>> usable in Rust, Larry you mentioned a minimal C API, that would make it >>>>>> much simpler to wrap to Rust, that would also mean in can be wrapped to >>>>>> many other languages, >>>>>> So far we didn't want to go the C route, but that might not be a bad >>>>>> idea since it would open the library a lot more and it might make it >>>>>> simpler to automate, at least the bulk of it, for Rust. >>>>>> >>>>>> We need to discuss the approach. >>>>>> >>>>>> On Sun, Oct 18, 2020 at 8:40 PM Anders Langlands < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Scott, yes please do add me to the repo I’d love to take a look >>>>>>> and pitch in as time allows. >>>>>>> >>>>>>> On Mon, 19 Oct 2020 at 13:43, Scott Wilson <[email protected]> >>>>>>> wrote: >>>>>>> >>>>>>>> Hey Anders, >>>>>>>> >>>>>>>> Cxx has so far been pretty okay. It's pretty manual (hopefully >>>>>>>> autocxx makes it better, but as far as I know, it's still nowhere >>>>>>>> ready for >>>>>>>> using it on OpenImageIO). Right now the process looks something like >>>>>>>> this: >>>>>>>> >>>>>>>> 1. Create a header/cpp file that contains all of your class methods >>>>>>>> as functions. >>>>>>>> 2. Create an unsafe Rust interferface that's a 1 to 1 copy of the >>>>>>>> C++ side. >>>>>>>> 3. Create a safe Rust interface. >>>>>>>> >>>>>>>> For me, the really nice thing is I don't need to worry about the >>>>>>>> C++ -> C -> Rust steps. It drops the C step, but I still need to write >>>>>>>> that >>>>>>>> C++ "ugly" interface. >>>>>>>> >>>>>>>> Also, if you want to join in on the fun, our repo is currently >>>>>>>> private while we get things to a working state. But, I can add you to >>>>>>>> the >>>>>>>> repo. Otherwise, I'm up for a discussion on how to take both designs >>>>>>>> and >>>>>>>> come up with the best one. >>>>>>>> >>>>>>>> On Sun, Oct 18, 2020 at 4:51 PM Anders Langlands < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Wrapping C in Rust is a two-stage process: first writing an >>>>>>>>> "unsafe" FFI binding to the C API, which is usually almost completely >>>>>>>>> automated with a crate called bindgen, then writing a "safe" crate >>>>>>>>> that >>>>>>>>> provides a Rust-y API using the unsafe FFI bindings. Wrapping C++ >>>>>>>>> means >>>>>>>>> writing a C API first, then binding that to Rust, which is what my >>>>>>>>> crate >>>>>>>>> does. >>>>>>>>> >>>>>>>>> I've been meaning to return to this (and OSL, OpenSubdiv and >>>>>>>>> others) at some point and try to make a project-specific C-binding >>>>>>>>> generator using libclang, as manually maintaining the C stubs is >>>>>>>>> laborious >>>>>>>>> and error-prone. >>>>>>>>> >>>>>>>>> Scott, I'd be curious to know how you're getting on with cxx, I've >>>>>>>>> been meaning to look into that. I'd be happy to collaborate on >>>>>>>>> something we >>>>>>>>> could integrate into the main project as Larry suggests. >>>>>>>>> >>>>>>>>> On Mon, 19 Oct 2020 at 12:30, Larry Gritz <[email protected]> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> Feel free to have the discussion on-list, I'm sure it would be of >>>>>>>>>> interest to many. >>>>>>>>>> >>>>>>>>>> If there was consensus on what the Rust APIs should look like, I >>>>>>>>>> would welcome adding a set of Rust bindings to the main OIIO >>>>>>>>>> distribution. >>>>>>>>>> Assuming that makes sense, I was thinking it would be much like we >>>>>>>>>> now have >>>>>>>>>> with the Python bindings. The advantage to making Rust bindings part >>>>>>>>>> of the >>>>>>>>>> main build would be that it could be built and tested as part of our >>>>>>>>>> CI, >>>>>>>>>> versioned along with the rest of OIIO, and essentially never allowed >>>>>>>>>> to >>>>>>>>>> break. Also, just like we would never accept a PR that added C++ >>>>>>>>>> functionality without making sure the Python bindings kept up, we >>>>>>>>>> could >>>>>>>>>> ensure that nothing is left out of the Rust bindings. While I can >>>>>>>>>> appreciate the cleanliness and independence of it being a separate >>>>>>>>>> project, >>>>>>>>>> I can't help but think that it will be a neverending nightmare to >>>>>>>>>> try to >>>>>>>>>> keep the bindings in sync with the main project. >>>>>>>>>> >>>>>>>>>> I don't know how automated it is to make Rust bindings for C (I >>>>>>>>>> know it's a PITA for C++), but if making Rust bindings is >>>>>>>>>> substantially >>>>>>>>>> easier if you had minimal plain C wrappers for the major C++ >>>>>>>>>> classes, I'm >>>>>>>>>> sure there would be a lot of happy consumers of that even outside >>>>>>>>>> the Rust >>>>>>>>>> interest group. >>>>>>>>>> >>>>>>>>>> I haven't had time to try Rust myself for any programming >>>>>>>>>> project, though I've followed it from afar and like the idea of >>>>>>>>>> helping >>>>>>>>>> that community. TBH, the main thing that keeps me from spending any >>>>>>>>>> time on >>>>>>>>>> Rust is just that I can't contemplate the hassle of trying to program >>>>>>>>>> without my favourite libraries, and having OIIO (and its many >>>>>>>>>> utilities >>>>>>>>>> that I reuse in basically everything I write) available in Rust will >>>>>>>>>> substantially lower the bar for me to dabble in it more. >>>>>>>>>> >>>>>>>>>> -- lg >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On Oct 18, 2020, at 4:12 PM, Scott Wilson <[email protected]> >>>>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>> Hey Anders, >>>>>>>>>> >>>>>>>>>> We were inspired by what you did, and also decided to see if we >>>>>>>>>> can take this in a slightly different direction/ use cxx. If you're >>>>>>>>>> interested in discussing the wrapper more we can take it off the >>>>>>>>>> list. >>>>>>>>>> >>>>>>>>>> On Sun, Oct 18, 2020 at 3:35 PM Anders Langlands < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> I also have a rust binding here if you're interested: >>>>>>>>>>> https://github.com/anderslanglands/oiio-rs >>>>>>>>>>> >>>>>>>>>>> On Sun, 18 Oct 2020 at 04:43, Scott Wilson < >>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>> >>>>>>>>>>>> Awesome, thank you very much! I'll try this out and see how >>>>>>>>>>>> badly I break things. >>>>>>>>>>>> >>>>>>>>>>>> On Sat., Oct. 17, 2020, 1:02 a.m. Larry Gritz, < >>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>> >>>>>>>>>>>>> If you know the true legal extent of the memory allocation in >>>>>>>>>>>>> which that data pointer is located (in this case, the beginning >>>>>>>>>>>>> and ending >>>>>>>>>>>>> of the vector, if you are passing a pointer to one of the >>>>>>>>>>>>> elements of that >>>>>>>>>>>>> vector), then I think you could certainly consider it an error if >>>>>>>>>>>>> any of >>>>>>>>>>>>> these addresses lay outside that buffer: >>>>>>>>>>>>> >>>>>>>>>>>>> data + xstride*width - 1 >>>>>>>>>>>>> data + ystride*height - 1 >>>>>>>>>>>>> data + ystride*(height - 1) + xstride*width - 1 >>>>>>>>>>>>> data + zstride*depth >>>>>>>>>>>>> data + zstride*(depth - 1) + ystride*height - 1 >>>>>>>>>>>>> data + zstride*(depth - 1) + ystride*(height - 1) + >>>>>>>>>>>>> xstride*width - 1 >>>>>>>>>>>>> >>>>>>>>>>>>> There may be a more succinct way to put that, but I think it >>>>>>>>>>>>> covers all the cases of + and - strides. >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> On Oct 17, 2020, at 12:42 AM, Scott Wilson < >>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> Thanks! I guess to come from this at a different angle, let's >>>>>>>>>>>>> say I'm doing something like this: >>>>>>>>>>>>> >>>>>>>>>>>>> std::vector<uint8_t> pixels(10*10*3*1); >>>>>>>>>>>>> ImageInput.read_image(TypeDesc::UINT8, @pixels[0]) >>>>>>>>>>>>> >>>>>>>>>>>>> Would there be a case where I could pick a stride value that >>>>>>>>>>>>> would fall outside the pixels vector? >>>>>>>>>>>>> >>>>>>>>>>>>> PS: Thanks! I'm working on this with a friend, and hope to >>>>>>>>>>>>> have something released in the near future. >>>>>>>>>>>>> >>>>>>>>>>>>> On Fri., Oct. 16, 2020, 11:47 p.m. Larry Gritz, < >>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>> >>>>>>>>>>>>>> Oops, my math was wrong (in an unimportant detail): If you >>>>>>>>>>>>>> are making a mosaic of 16x5 of these 10x10 images, it is 80 >>>>>>>>>>>>>> small images >>>>>>>>>>>>>> you are assembling in total, not 40. >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> On Oct 16, 2020, at 11:43 PM, Larry Gritz <[email protected]> >>>>>>>>>>>>>> wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>> The strides don't describe the size of the image, they are >>>>>>>>>>>>>> the spacing in memory of where you want the values to be placed >>>>>>>>>>>>>> upon being >>>>>>>>>>>>>> read (or taken from in order to write). There is no invalid set >>>>>>>>>>>>>> of strides, >>>>>>>>>>>>>> because the caller might want them to end up anywhere in memory. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Or am I misunderstanding? >>>>>>>>>>>>>> >>>>>>>>>>>>>> For a fully "contiguous" memory buffer where you intend for >>>>>>>>>>>>>> every plane, scanline, pixel, and channel immediately follows >>>>>>>>>>>>>> the previous >>>>>>>>>>>>>> one, then in our example the strides would be xstride=3, >>>>>>>>>>>>>> ystride=30, >>>>>>>>>>>>>> zstride=300. (Though for a 2D image, the zstride is not used.) >>>>>>>>>>>>>> >>>>>>>>>>>>>> Here's an example of where you might have a stride range that >>>>>>>>>>>>>> is wildly outside this: Let's say that you have 40 of these 10 x >>>>>>>>>>>>>> 10 x 3 x >>>>>>>>>>>>>> uint8 image files and you are trying to read them in and >>>>>>>>>>>>>> assemble them into >>>>>>>>>>>>>> a single RGBA mosaic image of 16x5 x 4 x uint8 (the additional >>>>>>>>>>>>>> channel is >>>>>>>>>>>>>> alpha, which you will separately fill in as 1.0 [or 255 uint8] >>>>>>>>>>>>>> because it's >>>>>>>>>>>>>> not in your RGB files). Here's a cartoon to illustrate this: >>>>>>>>>>>>>> >>>>>>>>>>>>>> +-----------------------------------------+ >>>>>>>>>>>>>> | | | | | | | | | | | | | | | | | | | | | | >>>>>>>>>>>>>> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| >>>>>>>>>>>>>> | | | | | | | | | | | | | | | | | | | | | | >>>>>>>>>>>>>> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| >>>>>>>>>>>>>> | | | | | | | | | |X| | | | | | | | | | | | >>>>>>>>>>>>>> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| >>>>>>>>>>>>>> | | | | | | | | | | | | | | | | | | | | | | >>>>>>>>>>>>>> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-| >>>>>>>>>>>>>> | | | | | | | | | | | | | | | | | | | | | | >>>>>>>>>>>>>> +-----------------------------------------+ >>>>>>>>>>>>>> >>>>>>>>>>>>>> Each of my little grid cells is a 10x10 image. But that 10x10 >>>>>>>>>>>>>> image denoted by the "X" needs to be placed in memory in the >>>>>>>>>>>>>> right portion >>>>>>>>>>>>>> of the 16x10 x 5x10 mosaic. So what are the strides we use for >>>>>>>>>>>>>> the read? >>>>>>>>>>>>>> Well, the xstride is 4 because we're making room for an alpha >>>>>>>>>>>>>> channel that >>>>>>>>>>>>>> wasn't present in the file, the ystride is 640 (= 10*16*4), >>>>>>>>>>>>>> because each >>>>>>>>>>>>>> scanline of the little 10x10 image that you read needs to be >>>>>>>>>>>>>> placed on the >>>>>>>>>>>>>> proper scanline of the 160x50 mosaic you are assembling in >>>>>>>>>>>>>> memory. >>>>>>>>>>>>>> >>>>>>>>>>>>>> -- lg >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> P.S. Woo-hoo for making a Rust wrapper. I think that's a >>>>>>>>>>>>>> totally great thing. >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> On Oct 16, 2020, at 10:46 PM, Scott Wilson < >>>>>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>>>>> >>>>>>>>>>>>>> I'm experimenting with a Rust wrapper for OIIO, and had some >>>>>>>>>>>>>> questions about the stride. >>>>>>>>>>>>>> >>>>>>>>>>>>>> Let's say I have an image that is 10x10 pixels, and 3 >>>>>>>>>>>>>> channels, and 1 byte per channel. What strides would be invalid >>>>>>>>>>>>>> for that >>>>>>>>>>>>>> image? I'm guessing that anything between -10 * 10 * 3 * 1 to 10 >>>>>>>>>>>>>> * 10 * 3 * >>>>>>>>>>>>>> 1 and the AutoStride would be valid, and everything else may try >>>>>>>>>>>>>> to access >>>>>>>>>>>>>> memory that isn't initialized. Is this assumption correct, or am >>>>>>>>>>>>>> I missing >>>>>>>>>>>>>> something? >>>>>>>>>>>>>> >>>>>>>>>>>>>> Thanks! >>>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>>>>> [email protected] >>>>>>>>>>>>>> >>>>>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> -- >>>>>>>>>>>>>> Larry Gritz >>>>>>>>>>>>>> [email protected] >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>>>>> [email protected] >>>>>>>>>>>>>> >>>>>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> -- >>>>>>>>>>>>>> Larry Gritz >>>>>>>>>>>>>> [email protected] >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> >>>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>>>>> [email protected] >>>>>>>>>>>>>> >>>>>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>>>>> >>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>>>> [email protected] >>>>>>>>>>>>> >>>>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> -- >>>>>>>>>>>>> Larry Gritz >>>>>>>>>>>>> [email protected] >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> >>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>>>> [email protected] >>>>>>>>>>>>> >>>>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>>>> >>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>>> [email protected] >>>>>>>>>>>> >>>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>>> >>>>>>>>>>> _______________________________________________ >>>>>>>>>>> Oiio-dev mailing list >>>>>>>>>>> [email protected] >>>>>>>>>>> >>>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>>> >>>>>>>>>> _______________________________________________ >>>>>>>>>> Oiio-dev mailing list >>>>>>>>>> [email protected] >>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> Larry Gritz >>>>>>>>>> [email protected] >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> _______________________________________________ >>>>>>>>>> Oiio-dev mailing list >>>>>>>>>> [email protected] >>>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>>> >>>>>>>>> _______________________________________________ >>>>>>>>> Oiio-dev mailing list >>>>>>>>> [email protected] >>>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> Oiio-dev mailing list >>>>>>>> [email protected] >>>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>>> >>>>>>> _______________________________________________ >>>>>>> Oiio-dev mailing list >>>>>>> [email protected] >>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>> >>>>>> _______________________________________________ >>>>>> Oiio-dev mailing list >>>>>> [email protected] >>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>> >>>>> _______________________________________________ >>>>> Oiio-dev mailing list >>>>> [email protected] >>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> >>>> >>>> -- >>>> Larry Gritz >>>> [email protected] >>>> >>>> >>>> >>>> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> >> >> -- >> Larry Gritz >> [email protected] >> >> >> >> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> >
_______________________________________________ Oiio-dev mailing list [email protected] http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
