Ah, the OpenTimelineIO is interesting. I see that they are not prefixing with a namespace.
> On Oct 19, 2020, at 8:58 PM, Scott Wilson <[email protected]> wrote: > > I am talking with some people on the ASWF Slack, and they pointed me to the > OpenImageIO timeline C bindings project, which probably has a lot of good > lessons learned/things to borrow. > > https://github.com/PixarAnimationStudios/OpenTimelineIO/pull/696 > <https://github.com/PixarAnimationStudios/OpenTimelineIO/pull/696> > https://github.com/PixarAnimationStudios/OpenTimelineIO/tree/c-otio > <https://github.com/PixarAnimationStudios/OpenTimelineIO/tree/c-otio> > On Mon, Oct 19, 2020 at 8:35 PM Scott Wilson <[email protected] > <mailto:[email protected]>> wrote: > Works for me! > > Also, some other questions. > > - In the case of TypeDesc, we could probably have a 1:1 interface between C > and C++. But something like ImageSpec would either have to replace the > std::string with *char or we may need to make ImageSpec completely opaque. If > we go for the latter, how do we want attrs such as width, height, etc to be > exposed? > - There's some cases where std::vectors are used. Two ways we could handle > this are either to have structs that represent an owned or borrowed array > (something like struct StringVector { String *ptr, size_t length }), or > functions take a pointer + length in the arguments and structs hold a pointer > and length. I personally like option 1, because it keeps all that information > close together, and it makes the APIs have less arguments. The only problem > with it that I can think of is how do we want to handle creating/deleting > those structs? And do we want to have structs that are explicitly owning the > data they point to, or borrowing them (to borrow some Rust terminology)? > - This may be a small thing, but when it comes to deleting objects, even if > they don't have pointers/own data, do we want to always include a Type_delete > method? For example, TypeDesc doesn't have/need a destructor. If we say > everything has a destructor, then would there be a problem with that? > - How do we want to handle overrides? For example, if we have > OIIO::ImageSpec.attribute("my_attr", 1.0), would we want to convert that into > OIIO_ImageSpec_attribute_float("my_attr", 1.0)? What about with an unsigned > integer? I'm assuming we'd want to call it > OIIO_ImageSpec_attribute_uint(...). Also, in ImageInput, we have spec() with > a reference to the ImageSpec, and spec(subimage, miplevel). I'm assuming the > first will be OIIO_ImageInput_spec(), and the second will be > OIIO_ImageInput_spec_with_subimage_miplevel(...) or something like that. > - Since we're probably going to be passing around ImageInput and ImageBuf as > pointers (since they're a unique_ptr in C++), do we want to always assume > that a pointer to an ImageInput/Output/Buf are not null, or add a check in > the code for that? > - Does OIIO have exceptions? Either way, probably want to make sure any > exceptions passed from C++ don't cross over to the other side. > > Unrelated, but I think I may have been making extra work for me with cxx in > Rust. We may not actually need the header, but I haven't confirmed that. > Either that, or we could probably put everything in the header. Either way, > it's not related to the C project. > > On Mon, Oct 19, 2020 at 8:10 PM Anders Langlands <[email protected] > <mailto:[email protected]>> wrote: > 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] > <mailto:[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 > <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 > <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 > <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] > <mailto:[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] >> <mailto:[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] <mailto:[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] >> <mailto:[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] >>> <mailto:[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 >>> <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] <mailto:[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 >>> <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 <http://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 <http://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] >>> <mailto:[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] >>> <mailto:[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] >>> <mailto:[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] >>> <mailto:[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] >>> <mailto:[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] >>>> <mailto:[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] <mailto:[email protected]>> wrote: >>>> I also have a rust binding here if you're interested: >>>> https://github.com/anderslanglands/oiio-rs >>>> <https://github.com/anderslanglands/oiio-rs> >>>> On Sun, 18 Oct 2020 at 04:43, Scott Wilson <[email protected] >>>> <mailto:[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] >>>> <mailto:[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] >>>>> <mailto:[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] >>>>> <mailto:[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] >>>>>> <mailto:[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] >>>>>>> <mailto:[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] <mailto:[email protected]> >>>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>>>> >>>>>> -- >>>>>> Larry Gritz >>>>>> [email protected] <mailto:[email protected]> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> _______________________________________________ >>>>>> Oiio-dev mailing list >>>>>> [email protected] <mailto:[email protected]> >>>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>>> >>>>> -- >>>>> Larry Gritz >>>>> [email protected] <mailto:[email protected]> >>>>> >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> Oiio-dev mailing list >>>>> [email protected] <mailto:[email protected]> >>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>>> _______________________________________________ >>>>> Oiio-dev mailing list >>>>> [email protected] <mailto:[email protected]> >>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> >>>> -- >>>> Larry Gritz >>>> [email protected] <mailto:[email protected]> >>>> >>>> >>>> >>>> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> >>> -- >>> Larry Gritz >>> [email protected] <mailto:[email protected]> >>> >>> >>> >>> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >> >> -- >> Larry Gritz >> [email protected] <mailto:[email protected]> >> >> >> >> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] <mailto:[email protected]> >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] <mailto:[email protected]> >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] <mailto:[email protected]> >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> > > -- > Larry Gritz > [email protected] <mailto:[email protected]> > > > > > _______________________________________________ > Oiio-dev mailing list > [email protected] <mailto:[email protected]> > http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org > <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> > _______________________________________________ > Oiio-dev mailing list > [email protected] <mailto:[email protected]> > http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org > <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> > _______________________________________________ > Oiio-dev mailing list > [email protected] <mailto:[email protected]> > http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org > <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
