I’d argue for Type_new and Type_delete when the underlying code is just calling “new Type” and “delete Type” to make that explicit. Then overloads would be Type_new_with_XXX.
On Tue, 20 Oct 2020 at 15:31, 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 >
_______________________________________________ Oiio-dev mailing list [email protected] http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
