Addon - Import and Export of HxA files #103810

Open
opened 2023-01-11 19:40:07 +01:00 by Soslan · 21 comments

Documentation
Github repository

This addon allows export/import of 3D models in HxA format(©Eskil Steenberg, [Github repo]], [ https:*www.youtube.com/watch?v=jlNSbSutPZE | Youtube presentation ) - a graphics format made with ease of implementation in mind.
(For an example from my own experience, the way vertex and index data is stored in HxA, you could plug these two arrays into Vulkan draw calls and get your mesh rendered on the screen. I imagine it's more or less the same in Dx12).
Features to date:

  • edge creases
  • bones
  • vertex weights
  • shapekeys
  • custom properties

I'm sure that at least some of the following is true:

  • I've forgotten to do something I should have
  • Some of the things in my code could've been done better from the standpoint of either Python usage or knowledge of Blender API/logic of how things are done in Blender.
    As such, I'm open to all and any criticism or feedback - anything to help me improve the addon(and my skills and knowledge, as a bonus!) in any way.
    Thank you.

EDIT: added a zip archive with the addon files
HxA_py-11-01-23_18-46-20.zip

[Documentation](https://github.com/SoslanGM/HxApy_Blender_import-export/blob/master/README.md) [Github repository ](https://github.com/SoslanGM/HxApy_Blender_import-export) This addon allows export/import of 3D models in HxA format(©Eskil Steenberg, [Github repo]], [[ https:*www.youtube.com/watch?v=jlNSbSutPZE | Youtube presentation ](https:*github.com/quelsolaar/HxA) ) - a graphics format made with ease of implementation in mind. (For an example from my own experience, the way vertex and index data is stored in HxA, you could plug these two arrays into Vulkan draw calls and get your mesh rendered on the screen. I imagine it's more or less the same in Dx12). Features to date: - edge creases - bones - vertex weights - shapekeys - custom properties I'm sure that at least some of the following is true: - I've forgotten to do something I should have - Some of the things in my code could've been done better from the standpoint of either Python usage or knowledge of Blender API/logic of how things are done in Blender. As such, I'm open to all and any criticism or feedback - anything to help me improve the addon(and my skills and knowledge, as a bonus!) in any way. Thank you. EDIT: added a zip archive with the addon files [HxA_py-11-01-23_18-46-20.zip](https://archive.blender.org/developer/F14145161/HxA_py-11-01-23_18-46-20.zip)
Soslan self-assigned this 2023-01-11 19:40:07 +01:00
Author

Added subscriber: @SoslanGM

Added subscriber: @SoslanGM

Added subscriber: @scurest

Added subscriber: @scurest

I haven't looked at it very carefully, but I can tell you a few things.


All the addon files need to be in a single directory named eg. io_scene_hxa. There should be an init.py file at the toplevel with your bl_info/register/unregister stuff. Look at eg io_scene_obj that ships with Blender for an example. Currently your zip dumps all the files into the toplevel of the addon directory.


Code style: functions are snake_case and should usually be named like verbs. You should format your code with autopep8 (or black or something). See the Blender Best Practices page.


It's worth looking at the best way to handle binary arrays and stuff at an early stage. For example, my guess is the fastest way to read a float3- [x] array from a file and make those the vertices of a mesh is probably

import array
verts = array.array("f")
verts.fromfile(f, 3 * n)
mesh.vertices.add(n)
mesh.vertices.foreach_set("co", verts)

There's also foreach_get you can look at using. You can use them with lists/array.arrays/numpy arrays. The glTF uses numpy arrays a lot. You'll have to see what's best for your use case.


Attempting to import the teapot.hxa example from the HxA repo tries to allocate a zillion bytes and crashes my computer. Looking in a hex editor, I'm not entirely sure this isn't teapot.hxa's fault though.

I haven't looked at it very carefully, but I can tell you a few things. ---- All the addon files need to be in a single directory named eg. `io_scene_hxa`. There should be an __init__.py file at the toplevel with your bl_info/register/unregister stuff. Look at eg `io_scene_obj` that ships with Blender for an example. Currently your zip dumps all the files into the toplevel of the addon directory. ----- Code style: functions are `snake_case` and should usually be named like verbs. You should format your code with autopep8 (or black or something). See the Blender [Best Practices](https://docs.blender.org/api/current/info_best_practice.html) page. ----- It's worth looking at the best way to handle binary arrays and stuff at an early stage. For example, my guess is the fastest way to read a float3- [x] array from a file and make those the vertices of a mesh is probably ``` import array verts = array.array("f") verts.fromfile(f, 3 * n) mesh.vertices.add(n) mesh.vertices.foreach_set("co", verts) ``` There's also [foreach_get](https://docs.blender.org/api/current/bpy.types.bpy_prop_collection.html#bpy.types.bpy_prop_collection.foreach_get) you can look at using. You can use them with lists/array.arrays/numpy arrays. The glTF uses numpy arrays a lot. You'll have to see what's best for your use case. ----- Attempting to import the [teapot.hxa](https://github.com/quelsolaar/HxA/blob/5f3b6d1fd8162efd5489ff88e35dcd13e1308c2e/teapot.hxa) example from the HxA repo tries to allocate a zillion bytes and crashes my computer. Looking in a hex editor, I'm not entirely sure this isn't teapot.hxa's fault though.
Author
  • it's a bit embarrassing to admit, but when I was starting the development I couldn't make a little test addon work with the init file. Now that I have everything else working, it's definitely worth it to go back and whip it into shape
  • I'll definitely fix the function names, though I have ran flake8 on my code and eliminated most of its grievances. Most :)
  • I'm not sure about teapot anymore(been a while since I did anything with it), but in this case it's definitely its fault - my tool is running on a version of hxa that assumes a few fixes that aren't in the original version yet, but we'll get rid of this divergence soon enough.
    In the meantime, here's a bit more meaty file for an example(showcases all the features(except for custom properties). Though it's poorly weight-painted, tough to do on a low-poly model):
    giraffe_armature.hxa

Thanks for the feedback, and I'll definitely look into and apply the rest of the fixes you suggested!

- it's a bit embarrassing to admit, but when I was starting the development I couldn't make a little test addon work with the init file. Now that I have everything else working, it's definitely worth it to go back and whip it into shape - I'll definitely fix the function names, though I have ran flake8 on my code and eliminated most of its grievances. Most :) - I'm not sure about teapot anymore(been a while since I did anything with it), but in this case it's definitely its fault - my tool is running on a version of hxa that assumes a few fixes that aren't in the original version yet, but we'll get rid of this divergence soon enough. In the meantime, here's a bit more meaty file for an example(showcases all the features(except for custom properties). Though it's poorly weight-painted, tough to do on a low-poly model): [giraffe_armature.hxa](https://archive.blender.org/developer/F14146066/giraffe_armature.hxa) Thanks for the feedback, and I'll definitely look into and apply the rest of the fixes you suggested!
Author

Fixes for

  • proper addon structure with io_scene_hxa folder, with init.py and the rest of scripts inside
  • associated fixes to the packing script(zip.py)
  • function and variable names
    are now in the repository and in this .zip archive.

HxA_py-16-01-23_15-59-44.zip

Binary arrays will take a bit more time.

EDIT: whoops, let a few bugs slip in.
EDIT1: said bugs squashed, zip file reinstated, code formatted with black and committed to repo.
My beautiful aligned equals signs :'(

Fixes for - proper addon structure with io_scene_hxa folder, with __init__.py and the rest of scripts inside - associated fixes to the packing script(zip.py) - function and variable names are now in the repository and in this .zip archive. [HxA_py-16-01-23_15-59-44.zip](https://archive.blender.org/developer/F14153136/HxA_py-16-01-23_15-59-44.zip) Binary arrays will take a bit more time. EDIT: whoops, let a few bugs slip in. EDIT1: said bugs squashed, zip file reinstated, code formatted with black and committed to repo. My beautiful aligned equals signs :'(

Cool, the zip installs correctly now.

It'd be better to have an actual io_scene_hxa folder in the Github repo though. So that folder would be exactly what gets placed in the addon directly / goes into the ZIP. The Readme/license/zip.py that shouldn't be distributed would be outside io_scene_hxa.

I read hxapy_header.py and hxapy_read_write.py, so I have some more code comments.

hxapy_header.py

  • You can use IntEnum to replace the hxa_node_type/hxa_node_type_dict stuff. It can automatically convert between strings/numbers.
from enum import IntEnum

class HXANodeType(IntEnum):
    META_ONLY = 0
    GEOMETRY = 1
    IMAGE = 2

# Example
HXANodeType.GEOMETRY
HXANodeType(1).name  # => "GEOMETRY"
HXANodeType["GEOMETRY"].value  # => 1

hxapy_read_write.py

  • Don't do print/exit stuff here, it makes it less reusable. Raise an exception instead of exit().
  • Instead of silent, looking into using the logging module or something. You can also pull the logging into reusable log_meta/log_layer/etc functions so its not duplicated.
  • Instead of taking a filename to read/write, take the file object f instead; this let's the caller control the file which is more flexible. They can do stuff like control the file buffering, or write it into a bytearray instead of a file, etc.
  • Not sure why you need stuff like hxa_dict["node_count"], just use len(hxa_dict["nodes"])? Removes the possibilty that these could be out of sync. Same for all name_lengths/counts/etc.
  • Not sure why layer_dict is its own function. Seems out of place.
  • Why do you use strings for the types (instead of integers directly)?
  • For struct fmt: instead of doing eg "<"+"d"*n, do f"<{n}d", it does the same thing.
  • For MDT_BINARY, skip struct.pack and just write the bytes directly.
  • This is a problem with the HxA docs, but the HXA_MDT_INT64 / hxa_uint64 *int64_value metadata type is apparently a typo, it should either be HXA_MDT_UINT64 / hxa_uint64 *uint64_value or HXA_MDT_INT64 / hxa_int64 *int64_value. So not sure if it should be Q or q...

Here's an idea for cleaning this file up, you can see if you like it better https://gist.github.com/scurest/db57ab732520c549bd1ed52233f53f43 (I didn't do logging though). Note particularly all the arrays go through read_array/write_array so you can change them easily. write_array will handle either a list, tuple, or array.array and try to do the fastest thing depending on the type.

Cool, the zip installs correctly now. It'd be better to have an actual io_scene_hxa folder in the Github repo though. So that folder would be exactly what gets placed in the addon directly / goes into the ZIP. The Readme/license/zip.py that shouldn't be distributed would be outside io_scene_hxa. I read hxapy_header.py and hxapy_read_write.py, so I have some more code comments. **hxapy_header.py** * You can use IntEnum to replace the hxa_node_type/hxa_node_type_dict stuff. It can automatically convert between strings/numbers. ``` from enum import IntEnum class HXANodeType(IntEnum): META_ONLY = 0 GEOMETRY = 1 IMAGE = 2 # Example HXANodeType.GEOMETRY HXANodeType(1).name # => "GEOMETRY" HXANodeType["GEOMETRY"].value # => 1 ``` **hxapy_read_write.py** * Don't do print/exit stuff here, it makes it less reusable. Raise an exception instead of exit(). * Instead of `silent`, looking into using the logging module or something. You can also pull the logging into reusable log_meta/log_layer/etc functions so its not duplicated. * Instead of taking a filename to read/write, take the file object `f` instead; this let's the caller control the file which is more flexible. They can do stuff like control the file buffering, or write it into a bytearray instead of a file, etc. * Not sure why you need stuff like `hxa_dict["node_count"]`, just use `len(hxa_dict["nodes"])`? Removes the possibilty that these could be out of sync. Same for all name_lengths/counts/etc. * Not sure why `layer_dict` is its own function. Seems out of place. * Why do you use strings for the types (instead of integers directly)? * For struct fmt: instead of doing eg `"<"+"d"*n`, do `f"<{n}d"`, it does the same thing. * For MDT_BINARY, skip struct.pack and just write the bytes directly. * This is a problem with the HxA docs, but the `HXA_MDT_INT64 / hxa_uint64 *int64_value` metadata type is apparently a typo, it should either be `HXA_MDT_UINT64 / hxa_uint64 *uint64_value` or `HXA_MDT_INT64 / hxa_int64 *int64_value`. So not sure if it should be `Q` or `q`... Here's an idea for cleaning this file up, you can see if you like it better https://gist.github.com/scurest/db57ab732520c549bd1ed52233f53f43 (I didn't do logging though). Note particularly all the arrays go through read_array/write_array so you can change them easily. write_array will handle either a list, tuple, or array.array and try to do the fastest thing depending on the type.
Author

Big thanks for your help, again! Seems like I got a good long to-do list, I'll get back with the next round of changes :)

I'll look into the thing with HxA docs...
As for the keeping lengths separate, it's to conform with the format, as well as to know ahead of time how many bytes I'll need for a thing while reading a file(if I understand your question correctly).

EDIT
Aha, my bad, I didn't understand your question correctly. You meant "why do you keep this thing as a separate value in the dictionary", not "why write them to a file". I guess I wanted to keep things as close as possible between the Python and C version for my own convenience initially, but now it's a good idea to do away with it, of course.

Big thanks for your help, again! Seems like I got a good long to-do list, I'll get back with the next round of changes :) I'll look into the thing with HxA docs... As for the keeping lengths separate, it's to conform with the format, as well as to know ahead of time how many bytes I'll need for a thing while reading a file(if I understand your question correctly). EDIT Aha, my bad, I didn't understand your question correctly. You meant "why do you keep this thing as a separate value in the dictionary", not "why write them to a file". I guess I wanted to keep things as close as possible between the Python and C version for my own convenience initially, but now it's a good idea to do away with it, of course.

Yeah, that's what I meant.

I'm going over some of export_hxa_py.py now.

  • Not real important, but why the _py.py filename?
  • Again, there's a lot of debug-print stuff. That's fine for developing, but it shouldn't go in the final code.
  • Also looks like some debugging jsonname = f"testdump_giraffearmature_{hxa_util.timestamp()}.json" stuff is left in.
  • [x for x in arm_ob.scale] => arm_ob.scale[:]
  • The code for adding metas/layers is really repetitive, you should try factoring it out. For example it could look like
metas.append(hxa_meta(
    name="meta meshname",
    data=me.name,
))

metas.append(hxa_meta(
    name="meta scale",
    data=ob.scale[:],
))

#etc
  • When does this exception happen?
  • You don't need to convert to a bmesh to get the verts/polys, you can use the mesh directly.
  • In export_payload, you bounce back and forth between using bpy.context.object and ob_mesh. Use ob_mesh consistently in case you ever want to change it.
  • You should make sure you're in OBJECT mode before you start exporting, see here in the OBJ exporter for how and why.
  • Just my opinion, but don't use HXA_CONVENTION_HARD_BASE_VERTEX_LAYER_COMPONENTS, just use 3. The indirection doesn't buy you anything.

I have a question about how edges work in HxA. There's the same number as corners? I guess it's per-polygon edges instead of shared edges like Blender has?

Yeah, that's what I meant. I'm going over some of export_hxa_py.py now. * Not real important, but why the `_py.py` filename? * Again, there's a lot of debug-print stuff. That's fine for developing, but it shouldn't go in the final code. * Also looks like some debugging `jsonname = f"testdump_giraffearmature_{hxa_util.timestamp()}.json"` stuff is left in. * `[x for x in arm_ob.scale]` => `arm_ob.scale[:]` * The code for adding metas/layers is really repetitive, you should try factoring it out. For example it could look like ``` metas.append(hxa_meta( name="meta meshname", data=me.name, )) metas.append(hxa_meta( name="meta scale", data=ob.scale[:], )) #etc ``` * When does [this exception](https://github.com/SoslanGM/HxApy_Blender_import-export/blob/08e0106ab067aee5576cba2f78924fa00fb0ff6d/export_hxa_py.py#L179) happen? * You don't need to convert to a bmesh to get the verts/polys, you can use the mesh directly. * In export_payload, you bounce back and forth between using `bpy.context.object` and `ob_mesh`. Use `ob_mesh` consistently in case you ever want to change it. * You should make sure you're in OBJECT mode before you start exporting, see [here](https://github.com/sobotka/blender-addons/blob/a9d4443c244f89399ec4bcc427e05a07950528cc/io_scene_obj/export_obj.py#L667-L669) in the OBJ exporter for how and why. * Just my opinion, but don't use `HXA_CONVENTION_HARD_BASE_VERTEX_LAYER_COMPONENTS`, just use `3`. The indirection doesn't buy you anything. --- I have a question about how edges work in HxA. There's the same number as corners? I guess it's per-polygon edges instead of shared edges like Blender has?

Okay, I finished import_hxa_py.py. You're probably tired of me now, so I'll just say the in locals() stuff is very odd. Much simpler way: meta_dict = {meta["name"]: meta for meta in metas} so you can easily look up metas by name.


Since I've read the whole thing now, my overall impression is honestly I don't really understand why you'd use HxA. The repo appears to be abandoned (you yourself have a PR fixing significant issues with no response for 5 months, and there are much older ones too), and you don't seem to even be able to build the tools in it. It doesn't seem like anyone uses it. An HxA file barely has any structure, it's all convention, basically it's just a dump of a bunch of whatever variables you like pulled out of Blender. Any consumer of .hxas exported from Blender would be substantially coupled to both Blender in general and this specific HxA exporter addon in particular.

Anyway that's just my personal opinion, but I'm not a Blender dev or anything.

Okay, I finished import_hxa_py.py. You're probably tired of me now, so I'll just say the `in locals()` stuff is very odd. Much simpler way: `meta_dict = {meta["name"]: meta for meta in metas}` so you can easily look up metas by name. --- Since I've read the whole thing now, my overall impression is honestly I don't really understand why you'd use HxA. The repo appears to be abandoned (you yourself have a PR fixing significant issues with no response for 5 months, and there are much older ones too), and you don't seem to even be able to build the tools in it. It doesn't seem like anyone uses it. An HxA file barely has any structure, it's all convention, basically it's just a dump of a bunch of whatever variables you like pulled out of Blender. Any consumer of .hxas exported from Blender would be substantially coupled to both Blender in general and this specific HxA exporter addon in particular. Anyway that's just my personal opinion, but I'm not a Blender dev or anything.
Author

On the contrary - I'm very grateful for all of your help. You're showing me a lot of stuff I've forgotten to do and a lot of features and "tricks" Python has that I had no idea about(I'm not the guy that reads a book on everything a language has to offer... I should probably change that). A lot of odd things you see in my code is either me being scared to change anything and move away from a working state - which now that everything works I have no excuses to not go back and straighten things out, or stuff that I saw other addons doing, again, during initial stages.
As for the state of format/repo and potential tools utilizing it with or without Blender - I won't go into too much detail here, but you'll have to trust my word it's definitely not dead :)

And again, thanks for your insights, definitely not tired of you, keep em coming :D

On the contrary - I'm very grateful for all of your help. You're showing me a lot of stuff I've forgotten to do and a lot of features and "tricks" Python has that I had no idea about(I'm not the guy that reads a book on everything a language has to offer... I should probably change that). A lot of odd things you see in my code is either me being scared to change anything and move away from a working state - which now that everything works I have no excuses to not go back and straighten things out, or stuff that I saw other addons doing, again, during initial stages. As for the state of format/repo and potential tools utilizing it with or without Blender - I won't go into too much detail here, but you'll have to trust my word it's definitely not dead :) And again, thanks for your insights, definitely not tired of you, keep em coming :D
Author

BOY... took me a while, but I think most of your suggestions have been implemented.
Your version of RW made it in with minimal changes, as I spent a bit inferring the steps you must've taken, and studying your code. At the end of the day, there wasn't much point not using yours(mostly).
The image stuff wasn't 100% according to my understanding of the format, so I wasn't comfortable admitting those.

I've a couple of questions:

  • you omitted utf8 in string processing -- talk to me about that. Are we future-proofing for all of Unicode? :D
  • you've also omitted struct.error, but seeming as it's only left in a single spot, I'll look later for what array library does to files that end abruptly.

And there's quite a few passes that will have to happen anyway... for example, for the exception that you've asked about. It's hit when we check whether a vertex belongs to a weight group. It's a grossly inefficient way of doing it, but I'm not aware of a better way to do that check in Python(there is in C, must exist here as well, but )
The _py are a callback to this being a Python version, as before this functionality was implemented by me in C. I don't think that's happening anymore(nor does it need to, probably), so I might drop the suffixes. But the idea was to differentiate the Python and C implementations namewise, though there's enough distinctions as is. I won't however drop the py from hxapy :) (as it is a strictly Python implementation of some of the facilities originating from the C format)

HxA_py-28-01-23_17-31-27.zip

Please tell me if I've forgotten anything(I must have, though I tried to keep track of things with a big checklist) or you see any other improvement opportunities. Big thanks as usual(as reflected in the header as well!)

BOY... took me a while, but I think most of your suggestions have been implemented. Your version of RW made it in with minimal changes, as I spent a bit inferring the steps you must've taken, and studying your code. At the end of the day, there wasn't much point not using yours(mostly). The image stuff wasn't 100% according to my understanding of the format, so I wasn't comfortable admitting those. I've a couple of questions: - you omitted utf8 in string processing -- talk to me about that. Are we future-proofing for all of Unicode? :D - you've also omitted struct.error, but seeming as it's only left in a single spot, I'll look later for what array library does to files that end abruptly. And there's quite a few passes that will have to happen anyway... for example, for the exception that you've asked about. It's hit when we check whether a vertex belongs to a weight group. It's a grossly inefficient way of doing it, but I'm not aware of a better way to do that check in Python(there is in C, must exist here as well, but ) The _py are a callback to this being a Python version, as before this functionality was implemented by me in C. I don't think that's happening anymore(nor does it need to, probably), so I might drop the suffixes. But the idea was to differentiate the Python and C implementations namewise, though there's enough distinctions as is. I won't however drop the py from hxapy :) (as it is a strictly Python implementation of some of the facilities originating from the C format) [HxA_py-28-01-23_17-31-27.zip](https://archive.blender.org/developer/F14206651/HxA_py-28-01-23_17-31-27.zip) Please tell me if I've forgotten anything(I must have, though I tried to keep track of things with a big checklist) or you see any other _improvement opportunities_. Big thanks as usual(as reflected in the header as well!)

you omitted utf8 in string processing -- talk to me about that.

utf8 is the default already (see str.encode and bytes.decode).

I'll look later for what array library does to files that end abruptly.

You get EOFError: read didn't return enough bytes.

It's hit when we check whether a vertex belongs to a weight group

Oh yeah, I see. You can go the other way round instead, loop over verts, then check what groups it's in.

    indexes_biglist = [[] for _ in vgroups]
    weights_biglist = [[] for _ in vgroups]
    for vi, vert in enumerate(mesh.vertices):
        for g in vert.groups:
            indexes_biglist[g.group].append(vi)
            weights_biglist[g.group].append(g.weight)

edit: What I meant for the importer is instead of

meta_location = (
    metas_present["meta location"]
    if "meta location" in metas_present.keys()
    else None
)

# then later on...

if meta_location:
    x, y, z = meta_location["data"]

    mesh_object.location.x = x
    mesh_object.location.y = y
    mesh_object.location.z = z

You would just do

if "meta location" in metas_present:
     mesh_object.location = metas_present["meta location"]["data"]

Though I think you probably actually want to use a function here so you can add some type checking in case the meta doesn't look like you expect.

> you omitted utf8 in string processing -- talk to me about that. utf8 is the default already (see [str.encode](https:*docs.python.org/3/library/stdtypes.html#str.encode) and [bytes.decode](https:*docs.python.org/3/library/stdtypes.html#bytes.decode)). > I'll look later for what array library does to files that end abruptly. You get EOFError: read didn't return enough bytes. > It's hit when we check whether a vertex belongs to a weight group Oh yeah, I see. You can go the other way round instead, loop over verts, then check what groups it's in. ``` indexes_biglist = [[] for _ in vgroups] weights_biglist = [[] for _ in vgroups] for vi, vert in enumerate(mesh.vertices): for g in vert.groups: indexes_biglist[g.group].append(vi) weights_biglist[g.group].append(g.weight) ``` ------- edit: What I meant for the importer is instead of ``` meta_location = ( metas_present["meta location"] if "meta location" in metas_present.keys() else None ) # then later on... if meta_location: x, y, z = meta_location["data"] mesh_object.location.x = x mesh_object.location.y = y mesh_object.location.z = z ``` You would just do ``` if "meta location" in metas_present: mesh_object.location = metas_present["meta location"]["data"] ``` Though I think you probably actually want to use a function here so you can add some type checking in case the meta doesn't look like you expect.

Something else I noticed

class HXAMetaDataType(IntEnum):
    HXA_MDT_INT64 = 0
    HXA_MDT_DOUBLE = 1
    HXA_MDT_NODE = 2
    HXA_MDT_TEXT = 3
    HXA_MDT_BINARY = 4
    HXA_MDT_META = 5
    HXA_MDT_COUNT = 6

 mtype = HXAMetaDataType(read_u8(f))

if mtype >= HXAMetaDataType.HXA_MDT_COUNT: ...

The > case cannot happen. Try HXAMetaDataType(9). You get ValueError: 9 is not a valid HXAMetaDataType. The mtype = HXAMetaDataType(read_u8(f)) line already checks that the type is valid. So just remove the fake _COUNT enum item and you don't need to check the mtype at all.

Something else I noticed ``` class HXAMetaDataType(IntEnum): HXA_MDT_INT64 = 0 HXA_MDT_DOUBLE = 1 HXA_MDT_NODE = 2 HXA_MDT_TEXT = 3 HXA_MDT_BINARY = 4 HXA_MDT_META = 5 HXA_MDT_COUNT = 6 mtype = HXAMetaDataType(read_u8(f)) if mtype >= HXAMetaDataType.HXA_MDT_COUNT: ... ``` The > case cannot happen. Try `HXAMetaDataType(9)`. You get ValueError: 9 is not a valid HXAMetaDataType. The `mtype = HXAMetaDataType(read_u8(f))` line already checks that the type is valid. So just remove the fake _COUNT enum item and you don't need to check the mtype at all.
Member

Added subscriber: @PratikPB2123

Added subscriber: @PratikPB2123
Author

Good point, removed the counts.
As for the metas - it is a bit clumsy, but easy to understand and there's not a lot of space for errors there. Unless absolutely necessary, I'd leave it as is.

As for your previous question about edges, Blender indeed only has a single edge between each pair of vertexes, but it's sometimes very useful to have two, so HxA counts two between each vertex pair(as is the general case).
Vertex weights - it might not matter for high fidelity models that are properly weight-painted(unlike my giraffe, hehe), but in C you'd look at groups associated with bones and then read their vertex indexes. No such luck here(as far as I can tell. Hope to be wrong)

Good point, removed the counts. As for the metas - it is a bit clumsy, but easy to understand and there's not a lot of space for errors there. Unless absolutely necessary, I'd leave it as is. As for your previous question about edges, Blender indeed only has a single edge between each pair of vertexes, but it's sometimes very useful to have two, so HxA counts two between each vertex pair(as is the general case). Vertex weights - it might not matter for high fidelity models that are properly weight-painted(unlike my giraffe, hehe), but in C you'd look at groups associated with bones and then read their vertex indexes. No such luck here(as far as I can tell. Hope to be wrong)

As for your previous question about edges, Blender indeed only has a single edge between each pair of vertexes, but it's sometimes very useful to have two, so HxA counts two between each vertex pair(as is the general case).

Between corner pairs, rather? But what's the ordering? My guess would be that edge i goes from corner i to corner (i+1), unless corner i is the last corner in the poly, in which case it goes from corner i to the first corner in the poly, ie

edge_order.png

The HxA repo doesn't seem to say anything about this.

Vertex weights

I don't understand what you mean. The code I posted should do the same thing as extract_weights.

> As for your previous question about edges, Blender indeed only has a single edge between each pair of vertexes, but it's sometimes very useful to have two, so HxA counts two between each vertex pair(as is the general case). Between corner pairs, rather? But what's the ordering? My guess would be that edge i goes from corner i to corner (i+1), unless corner i is the last corner in the poly, in which case it goes from corner i to the first corner in the poly, ie ![edge_order.png](https://archive.blender.org/developer/F14214945/edge_order.png) The HxA repo doesn't seem to say anything about this. > Vertex weights I don't understand what you mean. The code I posted should do the same thing as extract_weights.
Author

Yes, corners. I keep mixing them up.
And I think your diagram is correct.

Oh. My bad, I'll need to take a closer look at that snippet. I briefly looked at it a few times, not enough each time to have a coherent idea of what it does and what I should do with it :'D

Yes, corners. I keep mixing them up. And I think your diagram is correct. Oh. My bad, I'll need to take a closer look at that snippet. I briefly looked at it a few times, not enough each time to have a coherent idea of what it does and what I should do with it :'D

You removed the counts, but you didn't remove the checks with the counts in hxapy_read_write.py.

You removed the counts, but you didn't remove the checks with the counts in hxapy_read_write.py.
Author

Oh crap, I tried your suggestions for the meta holder variables, and then reset them. The checks deletion got reset as well.

Oh crap, I tried your suggestions for the meta holder variables, and then reset them. The checks deletion got reset as well.
Author

Applied your fix to the vertex weights. Over 2500x speedup - this is definitely the right way to go!

Applied your fix to the vertex weights. Over 2500x speedup - this is definitely the right way to go!
Author

About meta holder variables - a slight fix(at minimum) was necessary after all -- to prevent use before declaration error, I've missed that one.

About meta holder variables - a slight fix(at minimum) was necessary after all -- to prevent use before declaration error, I've missed that one.
Sign in to join this conversation.
No Milestone
No project
No Assignees
3 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender-addons#103810
No description provided.