orthoAPI.h 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. 
  2. #ifndef DFPSR_ORTHO
  3. #define DFPSR_ORTHO
  4. #include "../../DFPSR/includeFramework.h"
  5. namespace dsr {
  6. using Direction = int32_t;
  7. static const Direction ortho_dir360 = 8;
  8. static const Direction ortho_dir315 = 7;
  9. static const Direction ortho_dir270 = 6;
  10. static const Direction ortho_dir225 = 5;
  11. static const Direction ortho_dir180 = 4;
  12. static const Direction ortho_dir135 = 3;
  13. static const Direction ortho_dir90 = 2;
  14. static const Direction ortho_dir45 = 1;
  15. static const Direction ortho_dir0 = 0;
  16. inline int correctDirection(Direction direction) {
  17. return (int32_t)((uint32_t)((int32_t)direction + (ortho_dir360 * 1024)) % ortho_dir360);
  18. }
  19. // World 3D units
  20. // Tile = Diameter from one side to another along a standard tile
  21. // Used for expressing exact tile indices in games so that information can be stored efficiently
  22. // Mini-Tile = Tile / miniUnitsPerTile
  23. // Used to express locations in 3D without relying too much on non-deterministic floats
  24. static constexpr int ortho_miniUnitsPerTile = 1024;
  25. static constexpr float ortho_tilesPerMiniUnit = 1.0f / (float)ortho_miniUnitsPerTile;
  26. int ortho_roundToTile(int miniCoordinate);
  27. IVector3D ortho_roundToTile(const IVector3D& miniPosition);
  28. float ortho_miniToFloatingTile(int miniCoordinate);
  29. FVector3D ortho_miniToFloatingTile(const IVector3D& miniPosition);
  30. int ortho_floatingTileToMini(float tileCoordinate);
  31. IVector3D ortho_floatingTileToMini(const FVector3D& tilePosition);
  32. // TODO: Make sure that every conversion is derived from a single pixel-rounded world-to-screen transform
  33. // Do this by letting it be the only argument for construction using integers
  34. // Everything else will simply be derived from it on construction
  35. struct OrthoView {
  36. public:
  37. // Unique integer for identifying the view
  38. int id = -1;
  39. // Direction for rotating sprites
  40. Direction worldDirection = ortho_dir0; // How are sprites in the world rotated relative to the camera's point of view
  41. // The rotating transform from normal-space to world-space.
  42. // Light-space is a superset of normal-space with the origin around the camera. (Almost like camera-space but with Y straight up)
  43. FMatrix3x3 normalToWorldSpace;
  44. // Pixel aligned space (To ensure that moving one tile has the same number of pixels each time)
  45. IVector2D pixelOffsetPerTileX; // How many pixels does a sprite move per tile in X.
  46. IVector2D pixelOffsetPerTileZ; // How many pixels does a sprite move per tile in Z.
  47. int yPixelsPerTile = 0;
  48. // How pixels in the depth buffer maps to world-space coordinates in whole floating tiles.
  49. FMatrix3x3 screenDepthToWorldSpace;
  50. FMatrix3x3 worldSpaceToScreenDepth;
  51. // How pixels in the depth buffer maps to light-space coordinates in whole floating tiles.
  52. // The origin is at the center of the image.
  53. // The X and Y axis gives tile offsets in light space along the screen without depth information.
  54. // The Z axis gives tile offset per mini-tile unit of height in the depth buffer.
  55. FMatrix3x3 screenDepthToLightSpace;
  56. FMatrix3x3 lightSpaceToScreenDepth;
  57. // Conversion systems between rounded pixels and XZ tiles along Y = 0
  58. FMatrix2x2 roundedScreenPixelsToWorldTiles; // TODO: Replace with a screenToTile sub-set
  59. public:
  60. OrthoView() {}
  61. OrthoView(int id, const IVector2D roundedXAxis, const IVector2D roundedZAxis, int yPixelsPerTile, const FMatrix3x3 &normalToWorldSpace, Direction worldDirection);
  62. public:
  63. IVector2D miniTileOffsetToScreenPixel(const IVector3D& miniTileOffset) const;
  64. // Position is expressed in world space using mini units
  65. IVector2D miniTilePositionToScreenPixel(const IVector3D& position, const IVector2D& worldCenter) const;
  66. // Returns the 3D mini-tile units moved along the ground for the pixel offset
  67. // Only rotation and scaling for pixel offsets
  68. FVector3D pixelToTileOffset(const IVector2D& pixelOffset) const;
  69. IVector3D pixelToMiniOffset(const IVector2D& pixelOffset) const;
  70. // Returns the 3D mini-tile location for a certain pixel on the screen intersecting with the ground
  71. // Full transform for pixel locations
  72. IVector3D pixelToMiniPosition(const IVector2D& pixelLocation, const IVector2D& worldCenter) const;
  73. };
  74. // How to use the orthogonal system
  75. // * Place tiles in whole tile integer units
  76. // Multiply directly with pixelOffsetPerTileX and pixelOffsetPerTileZ to get deterministic pixel offsets
  77. // * Define sprites in mini units (1 tile = ortho_miniUnitsPerTile mini units)
  78. // First multiply mini units with yPixelsPerTile, pixelOffsetPerTileX and pixelOffsetPerTileZ for each 3D coordinate
  79. // Then divide by ortho_miniUnitsPerTile, which most processors should have custom instructions for handling quickly
  80. // With enough bits in the integers, the result should be steady and not shake around randomly
  81. struct OrthoSystem {
  82. public:
  83. static constexpr int maxCameraAngles = 8;
  84. static constexpr float diag = 0.707106781f; // cos(45 degrees) = Sqrt(2) / 2
  85. // Persistent settings
  86. float cameraTilt; // Camera coefficient. (-inf is straight down, -1 is diagonal down, 0 is horizontal)
  87. int pixelsPerTile; // The sideway length of a tile in pixels when seen from straight ahead.
  88. // Generated views
  89. OrthoView view[maxCameraAngles];
  90. private:
  91. // Update generated settings from persistent settings
  92. // Enforces a valid orthogonal camera system
  93. void update();
  94. public:
  95. OrthoSystem();
  96. OrthoSystem(float cameraTilt, int pixelsPerTile);
  97. explicit OrthoSystem(const ReadableString& content);
  98. public:
  99. IVector2D miniTileOffsetToScreenPixel(const IVector3D& miniTileOffset, int cameraIndex) const {
  100. return this->view[cameraIndex].miniTileOffsetToScreenPixel(miniTileOffset);
  101. }
  102. // Position is expressed in world space using mini units
  103. IVector2D miniTilePositionToScreenPixel(const IVector3D& position, int cameraIndex, const IVector2D& worldCenter) const {
  104. return this->view[cameraIndex].miniTilePositionToScreenPixel(position, worldCenter);
  105. }
  106. public:
  107. // Returns the 3D mini-tile units moved along the ground for the pixel offset
  108. // Only rotation and scaling for pixel offsets
  109. FVector3D pixelToTileOffset(const IVector2D& pixelOffset, int cameraIndex) const {
  110. return this->view[cameraIndex].pixelToTileOffset(pixelOffset);
  111. }
  112. IVector3D pixelToMiniOffset(const IVector2D& pixelOffset, int cameraIndex) const {
  113. return this->view[cameraIndex].pixelToMiniOffset(pixelOffset);
  114. }
  115. // Returns the 3D mini-tile location for a certain pixel on the screen intersecting with the ground
  116. // Full transform for pixel locations
  117. IVector3D pixelToMiniPosition(const IVector2D& pixelLocation, int cameraIndex, const IVector2D& worldCenter) const {
  118. return this->view[cameraIndex].pixelToMiniPosition(pixelLocation, worldCenter);
  119. }
  120. };
  121. }
  122. #endif