orthoAPI.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. 
  2. #include "orthoAPI.h"
  3. namespace dsr {
  4. OrthoView::OrthoView(int id, const IVector2D roundedXAxis, const IVector2D roundedZAxis, int yPixelsPerTile, const FMatrix3x3 &normalToWorldSpace, Direction worldDirection)
  5. : id(id), worldDirection(worldDirection), normalToWorldSpace(normalToWorldSpace),
  6. pixelOffsetPerTileX(roundedXAxis), pixelOffsetPerTileZ(roundedZAxis), yPixelsPerTile(yPixelsPerTile) {
  7. // Pixel aligned 3D transformation matrix from tile (x, y, z) to screen (x, y, h)
  8. FMatrix3x3 tileToScreen = FMatrix3x3(
  9. FVector3D(roundedXAxis.x, roundedXAxis.y, 0),
  10. FVector3D(0, -this->yPixelsPerTile, 1.0f),
  11. FVector3D(roundedZAxis.x, roundedZAxis.y, 0)
  12. );
  13. // Back from deep screen pixels to world tile coordinates
  14. FMatrix3x3 screenToTile = inverse(tileToScreen);
  15. // TODO: Obsolete
  16. this->roundedScreenPixelsToWorldTiles = inverse(FMatrix2x2(FVector2D(roundedXAxis.x, roundedXAxis.y), FVector2D(roundedZAxis.x, roundedZAxis.y)));
  17. // Save the conversion from screen-space to world-space in tile units
  18. this->screenDepthToWorldSpace = screenToTile;
  19. this->worldSpaceToScreenDepth = tileToScreen;
  20. // Save the conversion from screen-space to light-space in tile units
  21. this->screenDepthToLightSpace = FMatrix3x3(
  22. this->normalToWorldSpace.transformTransposed(screenToTile.xAxis),
  23. this->normalToWorldSpace.transformTransposed(screenToTile.yAxis),
  24. this->normalToWorldSpace.transformTransposed(screenToTile.zAxis)
  25. );
  26. this->lightSpaceToScreenDepth = inverse(this->screenDepthToLightSpace);
  27. }
  28. IVector2D OrthoView::miniTileOffsetToScreenPixel(const IVector3D& miniTileOffset) const {
  29. IVector2D centeredPixelLocation = this->pixelOffsetPerTileX * miniTileOffset.x + this->pixelOffsetPerTileZ * miniTileOffset.z;
  30. centeredPixelLocation.y -= miniTileOffset.y * this->yPixelsPerTile;
  31. return centeredPixelLocation / ortho_miniUnitsPerTile;
  32. }
  33. IVector2D OrthoView::miniTilePositionToScreenPixel(const IVector3D& position, const IVector2D& worldCenter) const {
  34. return this->miniTileOffsetToScreenPixel(position) + worldCenter;
  35. }
  36. FVector3D OrthoView::pixelToTileOffset(const IVector2D& pixelOffset) const {
  37. FVector2D xzTiles = this->roundedScreenPixelsToWorldTiles.transform(FVector2D(pixelOffset.x, pixelOffset.y));
  38. return FVector3D(xzTiles.x, 0.0f, xzTiles.y);
  39. }
  40. IVector3D OrthoView::pixelToMiniOffset(const IVector2D& pixelOffset) const {
  41. FVector3D tiles = this->pixelToTileOffset(pixelOffset);
  42. return IVector3D(ortho_floatingTileToMini(tiles.x), 0, ortho_floatingTileToMini(tiles.z));
  43. }
  44. IVector3D OrthoView::pixelToMiniPosition(const IVector2D& pixelLocation, const IVector2D& worldCenter) const {
  45. return this->pixelToMiniOffset(pixelLocation - worldCenter);
  46. }
  47. OrthoSystem::OrthoSystem() : cameraTilt(0), pixelsPerTile(0) {}
  48. OrthoSystem::OrthoSystem(float cameraTilt, int pixelsPerTile) : cameraTilt(cameraTilt), pixelsPerTile(pixelsPerTile) {
  49. this->update();
  50. }
  51. OrthoSystem::OrthoSystem(const ReadableString& content) {
  52. config_parse_ini(content, [this](const ReadableString& block, const ReadableString& key, const ReadableString& value) {
  53. if (string_length(block) == 0) {
  54. if (string_caseInsensitiveMatch(key, U"DownTiltPerThousand")) {
  55. this->cameraTilt = (float)string_toInteger(value) * -0.001f;
  56. } else if (string_caseInsensitiveMatch(key, U"PixelsPerTile")) {
  57. this->pixelsPerTile = string_toInteger(value);
  58. } else {
  59. printText("Unrecognized key \"", key, "\" in orthogonal camera configuration file.\n");
  60. }
  61. } else {
  62. printText("Unrecognized block \"", block, "\" in orthogonal camera configuration file.\n");
  63. }
  64. });
  65. this->update();
  66. }
  67. void OrthoSystem::update() {
  68. // Calculate y offset rounded to whole tiles to prevent random gaps in grids
  69. int yPixelsPerTile = (float)this->pixelsPerTile / sqrt(this->cameraTilt * this->cameraTilt + 1);
  70. // Define sprite directions
  71. FVector3D upAxis = FVector3D(0.0f, 1.0f, 0.0f);
  72. Direction worldDirections[8] = {ortho_dir315, ortho_dir45, ortho_dir135, ortho_dir225, ortho_dir0, ortho_dir90, ortho_dir180, ortho_dir270};
  73. // Define approximate camera systems just to get something axis aligned
  74. FMatrix3x3 cameraSystems[8];
  75. cameraSystems[0] = FMatrix3x3::makeAxisSystem(FVector3D(diag, this->cameraTilt, diag), upAxis);
  76. cameraSystems[1] = FMatrix3x3::makeAxisSystem(FVector3D(-diag, this->cameraTilt, diag), upAxis);
  77. cameraSystems[2] = FMatrix3x3::makeAxisSystem(FVector3D(-diag, this->cameraTilt, -diag), upAxis);
  78. cameraSystems[3] = FMatrix3x3::makeAxisSystem(FVector3D(diag, this->cameraTilt, -diag), upAxis);
  79. cameraSystems[4] = FMatrix3x3::makeAxisSystem(FVector3D( 0, this->cameraTilt, 1), upAxis);
  80. cameraSystems[5] = FMatrix3x3::makeAxisSystem(FVector3D(-1, this->cameraTilt, 0), upAxis);
  81. cameraSystems[6] = FMatrix3x3::makeAxisSystem(FVector3D( 0, this->cameraTilt,-1), upAxis);
  82. cameraSystems[7] = FMatrix3x3::makeAxisSystem(FVector3D( 1, this->cameraTilt, 0), upAxis);
  83. for (int a = 0; a < maxCameraAngles; a++) {
  84. // Define the coordinate system for normals
  85. FVector3D normalSystemDirection = cameraSystems[a].zAxis;
  86. normalSystemDirection.y = 0.0f;
  87. FMatrix3x3 normalToWorldSpace = FMatrix3x3::makeAxisSystem(normalSystemDirection, FVector3D(0.0f, 1.0f, 0.0f));
  88. // Create an axis system truncated inwards to whole pixels to prevent creating empty seams between tile aligned sprites
  89. Camera approximateCamera = Camera::createOrthogonal(Transform3D(FVector3D(), cameraSystems[a]), this->pixelsPerTile, this->pixelsPerTile, 0.5f);
  90. float halfTile = (float)this->pixelsPerTile * 0.5f;
  91. FVector2D XAxis = approximateCamera.worldToScreen(FVector3D(1.0f, 0.0f, 0.0f)).is - halfTile;
  92. FVector2D ZAxis = approximateCamera.worldToScreen(FVector3D(0.0f, 0.0f, 1.0f)).is - halfTile;
  93. this->view[a] = OrthoView(
  94. a,
  95. IVector2D((int)XAxis.x, (int)XAxis.y),
  96. IVector2D((int)ZAxis.x, (int)ZAxis.y),
  97. yPixelsPerTile,
  98. normalToWorldSpace,
  99. worldDirections[a]
  100. );
  101. }
  102. }
  103. int ortho_roundToTile(int miniCoordinate) {
  104. return roundDown(miniCoordinate + (ortho_miniUnitsPerTile / 2), ortho_miniUnitsPerTile);
  105. }
  106. IVector3D ortho_roundToTile(const IVector3D& miniPosition) {
  107. return IVector3D(ortho_roundToTile(miniPosition.x), miniPosition.y, ortho_roundToTile(miniPosition.z));
  108. }
  109. float ortho_miniToFloatingTile(int miniCoordinate) {
  110. return (float)miniCoordinate * ortho_tilesPerMiniUnit;
  111. }
  112. FVector3D ortho_miniToFloatingTile(const IVector3D& miniPosition) {
  113. return FVector3D(
  114. ortho_miniToFloatingTile(miniPosition.x),
  115. ortho_miniToFloatingTile(miniPosition.y),
  116. ortho_miniToFloatingTile(miniPosition.z)
  117. );
  118. }
  119. int ortho_floatingTileToMini(float tileCoordinate) {
  120. return (int)round((double)tileCoordinate * (double)ortho_miniUnitsPerTile);
  121. }
  122. IVector3D ortho_floatingTileToMini(const FVector3D& tilePosition) {
  123. return IVector3D(
  124. ortho_floatingTileToMini(tilePosition.x),
  125. ortho_floatingTileToMini(tilePosition.y),
  126. ortho_floatingTileToMini(tilePosition.z)
  127. );
  128. }
  129. }