// zlib open source license // // Copyright (c) 2017 to 2019 David Forsgren Piuva // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. #ifndef DFPSR_RENDER_MODEL_RENDERCORE #define DFPSR_RENDER_MODEL_RENDERCORE #include #include "Camera.h" #include "shader/Shader.h" #include "../../base/threading.h" #include "../../collection/List.h" namespace dsr { struct TriangleDrawData { // Color target ImageRgbaU8 *targetImage; // Depth target ImageF32 *depthBuffer; // When perspective is used, the depth buffer stores 1 / depth instead of linear depth. bool perspective; // The target blending method Filter filter; // Unprocessed triangle data in the standard layout TriangleInput triangleInput; // Function pointer to the method that will process the command DRAW_CALLBACK_TYPE processTriangle; TriangleDrawData(ImageRgbaU8 *targetImage, ImageF32 *depthBuffer, bool perspective, Filter filter, const TriangleInput &triangleInput, DRAW_CALLBACK_TYPE processTriangle) : targetImage(targetImage), depthBuffer(depthBuffer), perspective(perspective), filter(filter), triangleInput(triangleInput), processTriangle(processTriangle) {} }; struct TriangleDrawCommand : public TriangleDrawData { // Triangle corners and projection // Not a part of TriangleDrawData, because the draw command is made after clipping into multiple smaller triangles ITriangle2D triangle; // The vertex interpolation weights for each corner to allow clipping triangles without // looping the same vertex colors and texture coordinates on every sub-triangle // Corner A's weight = (subB.x, subC.x) // Corner B's weight = (subB.y, subC.y) // Corner C's weight = (subB.z, subC.z) // The final vertex weight of a corner becomes a linear interpolation of the three original vertex weights // (A * (1 - subB - subC)) + (B * subB) + (C * subC) FVector3D subB, subC; // Extra clipping in case that the receiver of the command goes out of bound IRect clipBound; // Late removal of triangles without having to shuffle around any data bool occluded; TriangleDrawCommand(const TriangleDrawData &triangleDrawData, const ITriangle2D &triangle, const FVector3D &subB, const FVector3D &subC, const IRect &clipBound) : TriangleDrawData(triangleDrawData), triangle(triangle), subB(subB), subC(subC), clipBound(clipBound), occluded(false) {} }; // Get the visibility state for the triangle as seen by the camera. // If clipFrustum is false, the culling test will be done with the actual bounds of the target image. // This is used to know when a triangle needs to be drawn. // If clipFrustum is true, the culling test will be done with extended clip bounds outside of the target image. // This is used to know when a triangle needs lossy clipping in floating-point coordinates // before it can be converted to integer coordinates without causing an overflow in rasterization. Visibility getTriangleVisibility(const ITriangle2D &triangle, const Camera &camera, bool clipFrustum); // Draws according to a draw command. void executeTriangleDrawing(const TriangleDrawCommand &command, const IRect &clipBound); // A queue of draw commands class CommandQueue { public: List buffer; void add(const TriangleDrawCommand &command); // Multi-threading will be disabled if jobCount equals 1. void execute(const IRect &clipBound, int jobCount = 12) const; void clear(); }; // Given a triangle and a shader that holds the additional vertex data, this method can be called to draw it. // Preconditions: // * triangle should have passed the triangle visibility test for the actual image bound. // Only construct the shader and make this call if "getTriangleVisibility(triangle, camera, false) != Visibility::Hidden" passed. // Otherwise, it will waste a lot of time on rasterizing triangles that are not even visible. // Given a set of triangle data, this method can automatically draw it using the fastest default shader. // Triangle culling is handled automatically but you might want to apply culling per model or something before drawing many triangles. // commandQueue can be null to render directly using a single thread. // targetImage can be null to avoid using the pixel shader. // depthBuffer can be null to render without depth buffering. void renderTriangleFromData( CommandQueue *commandQueue, ImageRgbaU8 *targetImage, ImageF32 *depthBuffer, const Camera &camera, const ProjectedPoint &posA, const ProjectedPoint &posB, const ProjectedPoint &posC, Filter filter, const TextureRgbaU8 *diffuse, const TextureRgbaU8 *light, const TriangleTexCoords &texCoords, const TriangleColors &colors ); void renderTriangleFromDataDepth(ImageF32 *depthBuffer, const Camera &camera, const ProjectedPoint &posA, const ProjectedPoint &posB, const ProjectedPoint &posC); } #endif