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

Reply via email to