modelAPI.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2019 David Forsgren Piuva
  4. //
  5. // This software is provided 'as-is', without any express or implied
  6. // warranty. In no event will the authors be held liable for any damages
  7. // arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it
  11. // freely, subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented; you must not
  14. // claim that you wrote the original software. If you use this software
  15. // in a product, an acknowledgment in the product documentation would be
  16. // appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such, and must not be
  19. // misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source
  22. // distribution.
  23. #include "modelAPI.h"
  24. #include "imageAPI.h"
  25. #include "../render/model/Model.h"
  26. #define MUST_EXIST(OBJECT, METHOD) if (OBJECT.get() == nullptr) { throwError("The " #OBJECT " handle was null in " #METHOD "\n"); }
  27. namespace dsr {
  28. Model model_create() {
  29. return std::make_shared<ModelImpl>();
  30. }
  31. Model model_clone(const Model& model) {
  32. MUST_EXIST(model,model_clone);
  33. return std::make_shared<ModelImpl>(model->filter, model->partBuffer, model->positionBuffer);
  34. }
  35. void model_setFilter(const Model& model, Filter filter) {
  36. MUST_EXIST(model,model_setFilter);
  37. model->filter = filter;
  38. }
  39. Filter model_getFilter(const Model& model) {
  40. MUST_EXIST(model,model_getFilter);
  41. return model->filter;
  42. }
  43. bool model_exists(const Model& model) {
  44. return model.get() != nullptr;
  45. }
  46. int model_addEmptyPart(Model& model, const String &name) {
  47. MUST_EXIST(model,model_addEmptyPart);
  48. return model->addEmptyPart(name);
  49. }
  50. int model_getNumberOfParts(const Model& model) {
  51. MUST_EXIST(model,model_getNumberOfParts);
  52. return model->getNumberOfParts();
  53. }
  54. void model_setPartName(Model& model, int partIndex, const String &name) {
  55. MUST_EXIST(model,model_setPartName);
  56. model->setPartName(partIndex, name);
  57. }
  58. String model_getPartName(const Model& model, int partIndex) {
  59. MUST_EXIST(model,model_getPartName);
  60. return model->getPartName(partIndex);
  61. }
  62. int model_getNumberOfPoints(const Model& model) {
  63. MUST_EXIST(model,model_getNumberOfPoints);
  64. return model->getNumberOfPoints();
  65. }
  66. FVector3D model_getPoint(const Model& model, int pointIndex) {
  67. MUST_EXIST(model,model_getPoint);
  68. return model->getPoint(pointIndex);
  69. }
  70. void model_setPoint(Model& model, int pointIndex, const FVector3D& position) {
  71. MUST_EXIST(model,model_setPoint);
  72. model->setPoint(pointIndex, position);
  73. }
  74. int model_findPoint(const Model& model, const FVector3D &position, float threshold) {
  75. MUST_EXIST(model,model_findPoint);
  76. return model->findPoint(position, threshold);
  77. }
  78. int model_addPoint(const Model& model, const FVector3D &position) {
  79. MUST_EXIST(model,model_addPoint);
  80. return model->addPoint(position);
  81. }
  82. int model_addPointIfNeeded(Model& model, const FVector3D &position, float threshold) {
  83. MUST_EXIST(model,model_addPointIfNeeded);
  84. return model->addPointIfNeeded(position, threshold);
  85. }
  86. int model_getVertexPointIndex(const Model& model, int partIndex, int polygonIndex, int vertexIndex) {
  87. MUST_EXIST(model,model_getVertexPointIndex);
  88. return model->getVertexPointIndex(partIndex, polygonIndex, vertexIndex);
  89. }
  90. void model_setVertexPointIndex(Model& model, int partIndex, int polygonIndex, int vertexIndex, int pointIndex) {
  91. MUST_EXIST(model,model_setVertexPointIndex);
  92. model->setVertexPointIndex(partIndex, polygonIndex, vertexIndex, pointIndex);
  93. }
  94. FVector3D model_getVertexPosition(const Model& model, int partIndex, int polygonIndex, int vertexIndex) {
  95. MUST_EXIST(model,model_getVertexPosition);
  96. return model->getVertexPosition(partIndex, polygonIndex, vertexIndex);
  97. }
  98. FVector4D model_getVertexColor(const Model& model, int partIndex, int polygonIndex, int vertexIndex) {
  99. MUST_EXIST(model,model_getVertexColor);
  100. return model->getVertexColor(partIndex, polygonIndex, vertexIndex);
  101. }
  102. void model_setVertexColor(Model& model, int partIndex, int polygonIndex, int vertexIndex, const FVector4D& color) {
  103. MUST_EXIST(model,model_setVertexColor);
  104. model->setVertexColor(partIndex, polygonIndex, vertexIndex, color);
  105. }
  106. FVector4D model_getTexCoord(const Model& model, int partIndex, int polygonIndex, int vertexIndex) {
  107. MUST_EXIST(model,model_getTexCoord);
  108. return model->getTexCoord(partIndex, polygonIndex, vertexIndex);
  109. }
  110. void model_setTexCoord(Model& model, int partIndex, int polygonIndex, int vertexIndex, const FVector4D& texCoord) {
  111. MUST_EXIST(model,model_setTexCoord);
  112. model->setTexCoord(partIndex, polygonIndex, vertexIndex, texCoord);
  113. }
  114. int model_addTriangle(Model& model, int partIndex, int pointA, int pointB, int pointC) {
  115. MUST_EXIST(model,model_addTriangle);
  116. return model->addPolygon(Polygon(pointA, pointB, pointC), partIndex);
  117. }
  118. int model_addQuad(Model& model, int partIndex, int pointA, int pointB, int pointC, int pointD) {
  119. MUST_EXIST(model,model_addQuad);
  120. return model->addPolygon(Polygon(pointA, pointB, pointC, pointD), partIndex);
  121. }
  122. int model_getNumberOfPolygons(const Model& model, int partIndex) {
  123. MUST_EXIST(model,model_getNumberOfPolygons);
  124. return model->getNumberOfPolygons(partIndex);
  125. }
  126. int model_getPolygonVertexCount(const Model& model, int partIndex, int polygonIndex) {
  127. MUST_EXIST(model,model_getPolygonVertexCount);
  128. return model->getPolygonVertexCount(partIndex, polygonIndex);
  129. }
  130. ImageRgbaU8 model_getDiffuseMap(const Model& model, int partIndex) {
  131. MUST_EXIST(model,model_getDiffuseMap);
  132. return model->getDiffuseMap(partIndex);
  133. }
  134. // TODO: Change the backend's argument order for partIndex or simply inline all of it's functionality
  135. void model_setDiffuseMap(Model& model, int partIndex, const ImageRgbaU8 &diffuseMap) {
  136. MUST_EXIST(model,model_setDiffuseMap);
  137. model->setDiffuseMap(diffuseMap, partIndex);
  138. }
  139. // TODO: Change the backend's argument order for partIndex or simply inline all of it's functionality
  140. void model_setDiffuseMapByName(Model& model, int partIndex, ResourcePool &pool, const String &filename) {
  141. MUST_EXIST(model,model_setDiffuseMapByName);
  142. model->setDiffuseMapByName(pool, filename, partIndex);
  143. }
  144. ImageRgbaU8 model_getLightMap(Model& model, int partIndex) {
  145. MUST_EXIST(model,model_getLightMap);
  146. return model->getLightMap(partIndex);
  147. }
  148. // TODO: Change the backend's argument order for partIndex or simply inline all of it's functionality
  149. void model_setLightMap(Model& model, int partIndex, const ImageRgbaU8 &lightMap) {
  150. MUST_EXIST(model,model_setLightMap);
  151. model->setLightMap(lightMap, partIndex);
  152. }
  153. // TODO: Change the backend's argument order for partIndex or simply inline all of it's functionality
  154. void model_setLightMapByName(Model& model, int partIndex, ResourcePool &pool, const String &filename) {
  155. MUST_EXIST(model,model_setLightMapByName);
  156. model->setLightMapByName(pool, filename, partIndex);
  157. }
  158. // Single-threaded rendering for the simple cases where you just want it to work
  159. void model_render(const Model& model, const Transform3D &modelToWorldTransform, ImageRgbaU8& colorBuffer, ImageF32& depthBuffer, const Camera &camera) {
  160. if (model.get() != nullptr) {
  161. model->render((CommandQueue*)nullptr, colorBuffer, depthBuffer, modelToWorldTransform, camera);
  162. }
  163. }
  164. void model_renderDepth(const Model& model, const Transform3D &modelToWorldTransform, ImageF32& depthBuffer, const Camera &camera) {
  165. if (model.get() != nullptr) {
  166. model->renderDepth(depthBuffer, modelToWorldTransform, camera);
  167. }
  168. }
  169. // Context for rendering multiple models at the same time for improved speed
  170. class RendererImpl {
  171. private:
  172. bool receiving = false; // Preventing version dependency by only allowing calls in the expected order
  173. ImageRgbaU8 colorBuffer;
  174. ImageF32 depthBuffer;
  175. CommandQueue commandQueue;
  176. public:
  177. RendererImpl() {}
  178. void beginFrame(ImageRgbaU8& colorBuffer, ImageF32& depthBuffer) {
  179. if (this->receiving) {
  180. throwError("Called renderer_begin on the same renderer twice without ending the previous batch!\n");
  181. }
  182. this->receiving = true;
  183. this->colorBuffer = colorBuffer;
  184. this->depthBuffer = depthBuffer;
  185. }
  186. void giveTask(const Model& model, const Transform3D &modelToWorldTransform, const Camera &camera) {
  187. if (!this->receiving) {
  188. throwError("Cannot call renderer_giveTask before renderer_begin!\n");
  189. }
  190. // TODO: Make an algorithm for selecting if the model should be queued as an instance or triangulated at once
  191. // An extra argument may choose to force an instance directly into the command queue
  192. // Because the model is being borrowed for vertex animation
  193. // To prevent the command queue from getting full hold as much as possible in a sorted list of instances
  194. // When the command queue is full, the solid
  195. model->render(&this->commandQueue, this->colorBuffer, this->depthBuffer, modelToWorldTransform, camera);
  196. }
  197. void endFrame() {
  198. if (!this->receiving) {
  199. throwError("Called renderer_end without renderer_begin!\n");
  200. }
  201. this->receiving = false;
  202. if (image_exists(this->colorBuffer)) {
  203. this->commandQueue.execute(IRect::FromSize(image_getWidth(this->colorBuffer), image_getHeight(this->colorBuffer)));
  204. } else if (image_exists(this->depthBuffer)) {
  205. this->commandQueue.execute(IRect::FromSize(image_getWidth(this->depthBuffer), image_getHeight(this->depthBuffer)));
  206. }
  207. this->commandQueue.clear();
  208. }
  209. };
  210. Renderer renderer_create() {
  211. return std::make_shared<RendererImpl>();
  212. }
  213. bool renderer_exists(const Renderer& renderer) {
  214. return renderer.get() != nullptr;
  215. }
  216. void renderer_begin(Renderer& renderer, ImageRgbaU8& colorBuffer, ImageF32& depthBuffer) {
  217. MUST_EXIST(renderer,renderer_begin);
  218. renderer->beginFrame(colorBuffer, depthBuffer);
  219. }
  220. // TODO: Synchronous setting
  221. // * Asynchronous (default)
  222. // Only works on models that are locked from further editing
  223. // Locked models can also be safely pooled for reuse then (ResourcePool)
  224. // * Synced (for animation)
  225. // Dispatch triangles directly to the command queue so that the current state of the model is captured
  226. // This allow rendering many instances using the same model at different times
  227. // Enabling vertex light, reflection maps and bone animation
  228. void renderer_giveTask(Renderer& renderer, const Model& model, const Transform3D &modelToWorldTransform, const Camera &camera) {
  229. MUST_EXIST(renderer,renderer_giveTask);
  230. if (model.get() != nullptr) {
  231. renderer->giveTask(model, modelToWorldTransform, camera);
  232. }
  233. }
  234. void renderer_end(Renderer& renderer) {
  235. MUST_EXIST(renderer,renderer_end);
  236. renderer->endFrame();
  237. }
  238. }