r3d_mesh_data.odin 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /* r3d_mesh_data.odin -- R3D Mesh Data Module.
  2. *
  3. * Copyright (c) 2025-2026 Le Juez Victor
  4. *
  5. * This software is provided 'as-is', without any express or implied warranty.
  6. * For conditions of distribution and use, see accompanying LICENSE file.
  7. */
  8. package r3d
  9. import rl "vendor:raylib"
  10. when ODIN_OS == .Windows {
  11. foreign import lib {
  12. "windows/libr3d.a",
  13. "system:raylib",
  14. "system:assimp",
  15. }
  16. } else when ODIN_OS == .Linux {
  17. foreign import lib {
  18. "linux/libr3d.a",
  19. "system:raylib",
  20. "system:assimp",
  21. }
  22. } else when ODIN_OS == .Darwin {
  23. foreign import lib {
  24. "darwin/libr3d.a",
  25. "system:raylib",
  26. "system:assimp",
  27. }
  28. }
  29. /**
  30. * @brief Represents a vertex and all its attributes for a mesh.
  31. */
  32. Vertex :: struct {
  33. position: rl.Vector3, /**< The 3D position of the vertex in object space. */
  34. texcoord: rl.Vector2, /**< The 2D texture coordinates (UV) for mapping textures. */
  35. normal: rl.Vector3, /**< The normal vector used for lighting calculations. */
  36. color: rl.Color, /**< Vertex color, in RGBA32. */
  37. tangent: rl.Vector4, /**< The tangent vector, used in normal mapping (often with a handedness in w). */
  38. boneIds: [4]i32, /**< Indices of up to 4 bones that influence this vertex (for skinning). */
  39. weights: [4]f32, /**< Corresponding bone weights (should sum to 1.0). Defines the influence of each bone. */
  40. }
  41. /**
  42. * @brief Represents a mesh stored in CPU memory.
  43. *
  44. * R3D_MeshData is the CPU-side container of a mesh. It stores vertex and index data,
  45. * and provides utility functions to generate, transform, and process geometry before
  46. * uploading it to the GPU as an R3D_Mesh.
  47. *
  48. * Think of it as a toolbox for procedural or dynamic mesh generation on the CPU.
  49. */
  50. MeshData :: struct {
  51. vertices: [^]Vertex, ///< Pointer to vertex data in CPU memory.
  52. indices: [^]u32, ///< Pointer to index data in CPU memory.
  53. vertexCount: i32, ///< Number of vertices.
  54. indexCount: i32, ///< Number of indices.
  55. }
  56. @(default_calling_convention="c", link_prefix="R3D_")
  57. foreign lib {
  58. /**
  59. * @brief Creates an empty mesh data container.
  60. *
  61. * Allocates memory for vertex and index buffers. All allocated buffers
  62. * are zero-initialized.
  63. *
  64. * @param vertexCount Number of vertices to allocate. Must be non-zero.
  65. * @param indexCount Number of indices to allocate. May be zero.
  66. * If zero, no index buffer is allocated.
  67. *
  68. * @return A new R3D_MeshData instance with allocated memory.
  69. */
  70. CreateMeshData :: proc(vertexCount: i32, indexCount: i32) -> MeshData ---
  71. /**
  72. * @brief Releases memory used by a mesh data container.
  73. * @param meshData R3D_MeshData to destroy.
  74. */
  75. UnloadMeshData :: proc(meshData: MeshData) ---
  76. /**
  77. * @brief Check if mesh data is valid.
  78. *
  79. * Returns true if the mesh data contains at least one vertex buffer
  80. * with a positive number of vertices.
  81. *
  82. * @param meshData Mesh data to check.
  83. * @return true if valid, false otherwise.
  84. */
  85. IsMeshDataValid :: proc(meshData: MeshData) -> bool ---
  86. /**
  87. * @brief Generate a quad mesh with specified dimensions, resolution, and orientation.
  88. *
  89. * Creates a flat rectangular quad mesh with customizable facing direction.
  90. * The mesh can be subdivided for higher resolution or displacement mapping.
  91. * The quad is centered at the origin and oriented according to the frontDir parameter,
  92. * which defines both the face direction and the surface normal.
  93. *
  94. * @param width Width of the quad along its local X axis.
  95. * @param length Length of the quad along its local Z axis.
  96. * @param resX Number of subdivisions along the width.
  97. * @param resZ Number of subdivisions along the length.
  98. * @param frontDir Direction vector defining the quad's front face and normal.
  99. * This vector will be normalized internally.
  100. *
  101. * @return Generated quad mesh structure with proper normals, tangents, and UVs.
  102. */
  103. GenMeshDataQuad :: proc(width: f32, length: f32, resX: i32, resZ: i32, frontDir: rl.Vector3) -> MeshData ---
  104. /**
  105. * @brief Generate a plane mesh with specified dimensions and resolution.
  106. *
  107. * Creates a flat plane mesh in the XZ plane, centered at the origin.
  108. * The mesh can be subdivided for higher resolution or displacement mapping.
  109. *
  110. * @param width Width of the plane along the X axis.
  111. * @param length Length of the plane along the Z axis.
  112. * @param resX Number of subdivisions along the X axis.
  113. * @param resZ Number of subdivisions along the Z axis.
  114. *
  115. * @return Generated plane mesh structure.
  116. */
  117. GenMeshDataPlane :: proc(width: f32, length: f32, resX: i32, resZ: i32) -> MeshData ---
  118. /**
  119. * @brief Generate a polygon mesh with specified number of sides.
  120. *
  121. * Creates a regular polygon mesh centered at the origin in the XY plane.
  122. * The polygon is generated with vertices evenly distributed around a circle.
  123. *
  124. * @param sides Number of sides for the polygon (minimum 3).
  125. * @param radius Radius of the circumscribed circle.
  126. * @param frontDir Direction vector defining the polygon's front face and normal.
  127. * This vector will be normalized internally.
  128. *
  129. * @return Generated polygon mesh structure.
  130. */
  131. GenMeshDataPoly :: proc(sides: i32, radius: f32, frontDir: rl.Vector3) -> MeshData ---
  132. /**
  133. * @brief Generate a cube mesh with specified dimensions.
  134. *
  135. * Creates a cube mesh centered at the origin with the specified width, height, and length.
  136. * Each face consists of two triangles with proper normals and texture coordinates.
  137. *
  138. * @param width Width of the cube along the X axis.
  139. * @param height Height of the cube along the Y axis.
  140. * @param length Length of the cube along the Z axis.
  141. *
  142. * @return Generated cube mesh structure.
  143. */
  144. GenMeshDataCube :: proc(width: f32, height: f32, length: f32) -> MeshData ---
  145. /**
  146. * @brief Generate a subdivided cube mesh with specified dimensions.
  147. *
  148. * Extension of R3D_GenMeshDataCube() allowing per-axis subdivision.
  149. * Each face can be tessellated along the X, Y, and Z axes according
  150. * to the provided resolutions.
  151. *
  152. * @param width Width of the cube along the X axis.
  153. * @param height Height of the cube along the Y axis.
  154. * @param length Length of the cube along the Z axis.
  155. * @param resX Number of subdivisions along the X axis.
  156. * @param resY Number of subdivisions along the Y axis.
  157. * @param resZ Number of subdivisions along the Z axis.
  158. *
  159. * @return Generated cube mesh structure.
  160. */
  161. GenMeshDataCubeEx :: proc(width: f32, height: f32, length: f32, resX: i32, resY: i32, resZ: i32) -> MeshData ---
  162. /**
  163. * @brief Generate a slope mesh by cutting a cube with a plane.
  164. *
  165. * Creates a slope mesh by slicing a cube with a plane that passes through the origin.
  166. * The plane is defined by its normal vector, and the portion of the cube on the side
  167. * opposite to the normal direction is kept. This allows creating ramps, wedges, and
  168. * angled surfaces with arbitrary orientations.
  169. *
  170. * @param width Width of the base cube along the X axis.
  171. * @param height Height of the base cube along the Y axis.
  172. * @param length Length of the base cube along the Z axis.
  173. * @param slopeNormal Normal vector of the cutting plane. The mesh keeps the portion
  174. * of the cube in the direction opposite to this normal.
  175. * Example: {-1, 0, 0} creates a ramp rising towards +X.
  176. * {0, 1, 0} creates a wedge with the slope facing up.
  177. * {-1.0, 1.0, 0} creates a 45° diagonal slope.
  178. *
  179. * @return Generated slope mesh structure.
  180. *
  181. * @note The normal vector will be automatically normalized internally.
  182. * @note The cutting plane always passes through the center of the cube (origin).
  183. */
  184. GenMeshDataSlope :: proc(width: f32, height: f32, length: f32, slopeNormal: rl.Vector3) -> MeshData ---
  185. /**
  186. * @brief Generate a sphere mesh with specified parameters.
  187. *
  188. * Creates a UV sphere mesh centered at the origin using latitude-longitude subdivision.
  189. * Higher ring and slice counts produce smoother spheres but with more vertices.
  190. *
  191. * @param radius Radius of the sphere.
  192. * @param rings Number of horizontal rings (latitude divisions).
  193. * @param slices Number of vertical slices (longitude divisions).
  194. *
  195. * @return Generated sphere mesh structure.
  196. */
  197. GenMeshDataSphere :: proc(radius: f32, rings: i32, slices: i32) -> MeshData ---
  198. /**
  199. * @brief Generate a hemisphere mesh with specified parameters.
  200. *
  201. * Creates a half-sphere mesh (dome) centered at the origin, extending upward in the Y axis.
  202. * Uses the same UV sphere generation technique as R3D_GenMeshSphere but only the upper half.
  203. *
  204. * @param radius Radius of the hemisphere.
  205. * @param rings Number of horizontal rings (latitude divisions).
  206. * @param slices Number of vertical slices (longitude divisions).
  207. *
  208. * @return Generated hemisphere mesh structure.
  209. */
  210. GenMeshDataHemiSphere :: proc(radius: f32, rings: i32, slices: i32) -> MeshData ---
  211. /**
  212. * @brief Generate a cylinder mesh with specified parameters.
  213. *
  214. * Creates a mesh centered at the origin, extending along the Y axis.
  215. * The mesh includes top and bottom caps and smooth side surfaces.
  216. * A cone is produced when bottomRadius and topRadius differ.
  217. *
  218. * @param bottomRadius Radius of the bottom cap.
  219. * @param topRadius Radius of the top cap.
  220. * @param height Height of the shape along the Y axis.
  221. * @param slices Number of radial subdivisions around the shape.
  222. *
  223. * @return Generated mesh structure.
  224. */
  225. GenMeshDataCylinder :: proc(bottomRadius: f32, topRadius: f32, height: f32, slices: i32) -> MeshData ---
  226. /**
  227. * @brief Generate a capsule mesh with specified parameters.
  228. *
  229. * Creates a capsule mesh centered at the origin, extending along the Y axis.
  230. * The capsule consists of a cylindrical body with hemispherical caps on both ends.
  231. * The total height of the capsule is height + 2 * radius.
  232. *
  233. * @param radius Radius of the capsule (both cylindrical body and hemispherical caps).
  234. * @param height Height of the cylindrical portion along the Y axis.
  235. * @param rings Total number of latitudinal subdivisions for both hemispheres combined.
  236. * @param slices Number of radial subdivisions around the shape.
  237. *
  238. * @return Generated mesh structure.
  239. */
  240. GenMeshDataCapsule :: proc(radius: f32, height: f32, rings: i32, slices: i32) -> MeshData ---
  241. /**
  242. * @brief Generate a torus mesh with specified parameters.
  243. *
  244. * Creates a torus (donut shape) mesh centered at the origin in the XZ plane.
  245. * The torus is defined by a major radius (distance from center to tube center)
  246. * and a minor radius (tube thickness).
  247. *
  248. * @param radius Major radius of the torus (distance from center to tube center).
  249. * @param size Minor radius of the torus (tube thickness/radius).
  250. * @param radSeg Number of segments around the major radius.
  251. * @param sides Number of sides around the tube cross-section.
  252. *
  253. * @return Generated torus mesh structure.
  254. */
  255. GenMeshDataTorus :: proc(radius: f32, size: f32, radSeg: i32, sides: i32) -> MeshData ---
  256. /**
  257. * @brief Generate a trefoil knot mesh with specified parameters.
  258. *
  259. * Creates a trefoil knot mesh, which is a mathematical knot shape.
  260. * Similar to a torus but with a twisted, knotted topology.
  261. *
  262. * @param radius Major radius of the knot.
  263. * @param size Minor radius (tube thickness) of the knot.
  264. * @param radSeg Number of segments around the major radius.
  265. * @param sides Number of sides around the tube cross-section.
  266. *
  267. * @return Generated trefoil knot mesh structure.
  268. */
  269. GenMeshDataKnot :: proc(radius: f32, size: f32, radSeg: i32, sides: i32) -> MeshData ---
  270. /**
  271. * @brief Generate a terrain mesh from a heightmap image.
  272. *
  273. * Creates a terrain mesh by interpreting the brightness values of a heightmap image
  274. * as height values. The resulting mesh represents a 3D terrain surface.
  275. *
  276. * @param heightmap rl.Image containing height data (grayscale values represent elevation).
  277. * @param size 3D vector defining the terrain dimensions (width, max height, depth).
  278. *
  279. * @return Generated heightmap terrain mesh structure.
  280. */
  281. GenMeshDataHeightmap :: proc(heightmap: rl.Image, size: rl.Vector3) -> MeshData ---
  282. /**
  283. * @brief Generate a voxel-style mesh from a cubicmap image.
  284. *
  285. * Creates a mesh composed of cubes based on a cubicmap image, where each pixel
  286. * represents the presence or absence of a cube at that position. Useful for
  287. * creating voxel-based or block-based geometry.
  288. *
  289. * @param cubicmap rl.Image where pixel values determine cube placement.
  290. * @param cubeSize 3D vector defining the size of each individual cube.
  291. *
  292. * @return Generated cubicmap mesh structure.
  293. */
  294. GenMeshDataCubicmap :: proc(cubicmap: rl.Image, cubeSize: rl.Vector3) -> MeshData ---
  295. /**
  296. * @brief Creates a deep copy of an existing mesh data container.
  297. * @param meshData Source mesh data to duplicate.
  298. * @return A new R3D_MeshData containing a copy of the source data.
  299. */
  300. DuplicateMeshData :: proc(meshData: MeshData) -> MeshData ---
  301. /**
  302. * @brief Merges two mesh data containers into a single one.
  303. * @param a First mesh data.
  304. * @param b Second mesh data.
  305. * @return A new R3D_MeshData containing the merged geometry.
  306. */
  307. MergeMeshData :: proc(a: MeshData, b: MeshData) -> MeshData ---
  308. /**
  309. * @brief Translates all vertices by a given offset.
  310. * @param meshData Mesh data to modify.
  311. * @param translation Offset to apply to all vertex positions.
  312. */
  313. TranslateMeshData :: proc(meshData: ^MeshData, translation: rl.Vector3) ---
  314. /**
  315. * @brief Rotates all vertices using a quaternion.
  316. * @param meshData Mesh data to modify.
  317. * @param rotation rl.Quaternion representing the rotation.
  318. */
  319. RotateMeshData :: proc(meshData: ^MeshData, rotation: rl.Quaternion) ---
  320. /**
  321. * @brief Scales all vertices by given factors.
  322. * @param meshData Mesh data to modify.
  323. * @param scale Scaling factors for each axis.
  324. */
  325. ScaleMeshData :: proc(meshData: ^MeshData, scale: rl.Vector3) ---
  326. /**
  327. * @brief Generates planar UV coordinates.
  328. * @param meshData Mesh data to modify.
  329. * @param uvScale Scaling factors for UV coordinates.
  330. * @param axis Axis along which to project the planar mapping.
  331. */
  332. GenMeshDataUVsPlanar :: proc(meshData: ^MeshData, uvScale: rl.Vector2, axis: rl.Vector3) ---
  333. /**
  334. * @brief Generates spherical UV coordinates.
  335. * @param meshData Mesh data to modify.
  336. */
  337. GenMeshDataUVsSpherical :: proc(meshData: ^MeshData) ---
  338. /**
  339. * @brief Generates cylindrical UV coordinates.
  340. * @param meshData Mesh data to modify.
  341. */
  342. GenMeshDataUVsCylindrical :: proc(meshData: ^MeshData) ---
  343. /**
  344. * @brief Computes vertex normals from triangle geometry.
  345. * @param meshData Mesh data to modify.
  346. */
  347. GenMeshDataNormals :: proc(meshData: ^MeshData) ---
  348. /**
  349. * @brief Computes vertex tangents based on existing normals and UVs.
  350. * @param meshData Mesh data to modify.
  351. */
  352. GenMeshDataTangents :: proc(meshData: ^MeshData) ---
  353. /**
  354. * @brief Calculates the axis-aligned bounding box of the mesh.
  355. * @param meshData Mesh data to analyze.
  356. * @return The computed bounding box.
  357. */
  358. CalculateMeshDataBoundingBox :: proc(meshData: MeshData) -> rl.BoundingBox ---
  359. }