Browse Source

Made debug drawing of octree to allow finding the remaining bugs.

David Piuva 5 years ago
parent
commit
c9ccc57bb3
2 changed files with 99 additions and 53 deletions
  1. 95 53
      Source/SDK/SpriteEngine/spriteAPI.cpp
  2. 4 0
      Source/SDK/SpriteEngine/spriteAPI.h

+ 95 - 53
Source/SDK/SpriteEngine/spriteAPI.cpp

@@ -416,6 +416,63 @@ public:
 	}
 	}
 };
 };
 
 
+IVector3D getBoxCorner(const IVector3D& minBound, const IVector3D& maxBound, int cornerIndex) {
+	assert(cornerIndex >= 0 && cornerIndex < 8);
+	return IVector3D(
+	  ((uint32_t)cornerIndex & 1u) ? maxBound.x : minBound.x,
+	  ((uint32_t)cornerIndex & 2u) ? maxBound.y : minBound.y,
+	  ((uint32_t)cornerIndex & 4u) ? maxBound.z : minBound.z
+	);
+}
+
+static bool orthoCullingTest(const OrthoView& ortho, const IVector3D& minBound, const IVector3D& maxBound, const IRect& seenRegion) {
+	IVector2D corners[8];
+	for (int c = 0; c < 8; c++) {
+		corners[c] = ortho.miniTileOffsetToScreenPixel(getBoxCorner(minBound, maxBound, c));
+	}
+	if (corners[0].x < seenRegion.left()
+	 && corners[1].x < seenRegion.left()
+	 && corners[2].x < seenRegion.left()
+	 && corners[3].x < seenRegion.left()
+	 && corners[4].x < seenRegion.left()
+	 && corners[5].x < seenRegion.left()
+	 && corners[6].x < seenRegion.left()
+	 && corners[7].x < seenRegion.left()) {
+		return false;
+	}
+	if (corners[0].x > seenRegion.right()
+	 && corners[1].x > seenRegion.right()
+	 && corners[2].x > seenRegion.right()
+	 && corners[3].x > seenRegion.right()
+	 && corners[4].x > seenRegion.right()
+	 && corners[5].x > seenRegion.right()
+	 && corners[6].x > seenRegion.right()
+	 && corners[7].x > seenRegion.right()) {
+		return false;
+	}
+	if (corners[0].y < seenRegion.top()
+	 && corners[1].y < seenRegion.top()
+	 && corners[2].y < seenRegion.top()
+	 && corners[3].y < seenRegion.top()
+	 && corners[4].y < seenRegion.top()
+	 && corners[5].y < seenRegion.top()
+	 && corners[6].y < seenRegion.top()
+	 && corners[7].y < seenRegion.top()) {
+		return false;
+	}
+	if (corners[0].y > seenRegion.bottom()
+	 && corners[1].y > seenRegion.bottom()
+	 && corners[2].y > seenRegion.bottom()
+	 && corners[3].y > seenRegion.bottom()
+	 && corners[4].y > seenRegion.bottom()
+	 && corners[5].y > seenRegion.bottom()
+	 && corners[6].y > seenRegion.bottom()
+	 && corners[7].y > seenRegion.bottom()) {
+		return false;
+	}
+	return true;
+}
+
 // BlockState keeps track of when the background itself needs to update from static objects being created or destroyed
 // BlockState keeps track of when the background itself needs to update from static objects being created or destroyed
 enum class BlockState {
 enum class BlockState {
 	Unused,
 	Unused,
@@ -433,64 +490,12 @@ public:
 	OrderedImageRgbaU8 normalBuffer;
 	OrderedImageRgbaU8 normalBuffer;
 	AlignedImageF32 heightBuffer;
 	AlignedImageF32 heightBuffer;
 private:
 private:
-	IVector3D getBoxCorner(const IVector3D& minBound, const IVector3D& maxBound, int cornerIndex) {
-		assert(cornerIndex >= 0 && cornerIndex < 8);
-		return IVector3D(
-		  ((uint32_t)cornerIndex & 1u) ? maxBound.x : minBound.x,
-		  ((uint32_t)cornerIndex & 2u) ? maxBound.y : minBound.y,
-		  ((uint32_t)cornerIndex & 4u) ? maxBound.z : minBound.z
-		);
-	}
 	// Pre-condition: diffuseBuffer must be cleared unless sprites cover the whole block
 	// Pre-condition: diffuseBuffer must be cleared unless sprites cover the whole block
 	void draw(Octree<SpriteInstance>& sprites, Octree<ModelInstance>& models, const OrthoView& ortho) {
 	void draw(Octree<SpriteInstance>& sprites, Octree<ModelInstance>& models, const OrthoView& ortho) {
 		image_fill(this->normalBuffer, ColorRgbaI32(128));
 		image_fill(this->normalBuffer, ColorRgbaI32(128));
 		image_fill(this->heightBuffer, -std::numeric_limits<float>::max());
 		image_fill(this->heightBuffer, -std::numeric_limits<float>::max());
 		OcTreeFilter orthoCullingFilter = [ortho,this](const IVector3D& minBound, const IVector3D& maxBound){
 		OcTreeFilter orthoCullingFilter = [ortho,this](const IVector3D& minBound, const IVector3D& maxBound){
-			IVector2D corners[8];
-			for (int c = 0; c < 8; c++) {
-				corners[c] = ortho.miniTileOffsetToScreenPixel(getBoxCorner(minBound, maxBound, c));
-			}
-			if (corners[0].x < this->worldRegion.left()
-			 && corners[1].x < this->worldRegion.left()
-			 && corners[2].x < this->worldRegion.left()
-			 && corners[3].x < this->worldRegion.left()
-			 && corners[4].x < this->worldRegion.left()
-			 && corners[5].x < this->worldRegion.left()
-			 && corners[6].x < this->worldRegion.left()
-			 && corners[7].x < this->worldRegion.left()) {
-				return false;
-			}
-			if (corners[0].x > this->worldRegion.right()
-			 && corners[1].x > this->worldRegion.right()
-			 && corners[2].x > this->worldRegion.right()
-			 && corners[3].x > this->worldRegion.right()
-			 && corners[4].x > this->worldRegion.right()
-			 && corners[5].x > this->worldRegion.right()
-			 && corners[6].x > this->worldRegion.right()
-			 && corners[7].x > this->worldRegion.right()) {
-				return false;
-			}
-			if (corners[0].y < this->worldRegion.top()
-			 && corners[1].y < this->worldRegion.top()
-			 && corners[2].y < this->worldRegion.top()
-			 && corners[3].y < this->worldRegion.top()
-			 && corners[4].y < this->worldRegion.top()
-			 && corners[5].y < this->worldRegion.top()
-			 && corners[6].y < this->worldRegion.top()
-			 && corners[7].y < this->worldRegion.top()) {
-				return false;
-			}
-			if (corners[0].y > this->worldRegion.bottom()
-			 && corners[1].y > this->worldRegion.bottom()
-			 && corners[2].y > this->worldRegion.bottom()
-			 && corners[3].y > this->worldRegion.bottom()
-			 && corners[4].y > this->worldRegion.bottom()
-			 && corners[5].y > this->worldRegion.bottom()
-			 && corners[6].y > this->worldRegion.bottom()
-			 && corners[7].y > this->worldRegion.bottom()) {
-				return false;
-			}
-			return true;
+			return orthoCullingTest(ortho, minBound, maxBound, this->worldRegion);
 		};
 		};
 		sprites.map(orthoCullingFilter, [this, ortho](SpriteInstance& sprite, const IVector3D origin, const IVector3D minBound, const IVector3D maxBound){
 		sprites.map(orthoCullingFilter, [this, ortho](SpriteInstance& sprite, const IVector3D origin, const IVector3D minBound, const IVector3D maxBound){
 			drawSprite(sprite, ortho, -this->worldRegion.upperLeft(), this->heightBuffer, this->diffuseBuffer, this->normalBuffer);
 			drawSprite(sprite, ortho, -this->worldRegion.upperLeft(), this->heightBuffer, this->diffuseBuffer, this->normalBuffer);
@@ -867,6 +872,43 @@ void spriteWorld_draw(SpriteWorld& world, AlignedImageRgbaU8& colorTarget) {
 	world->draw(colorTarget);
 	world->draw(colorTarget);
 }
 }
 
 
+#define BOX_LINE(INDEX_A, INDEX_B) draw_line(target, corners[INDEX_A].x, corners[INDEX_A].y, corners[INDEX_B].x, corners[INDEX_B].y, color);
+void debugDrawBound(SpriteWorld& world, const IVector2D& worldCenter, AlignedImageRgbaU8& target, const ColorRgbaI32& color, const IVector3D& minBound, const IVector3D& maxBound) {
+	IVector2D corners[8];
+	for (int c = 0; c < 8; c++) {
+		// TODO: Convert to real screen pixels using the camera offset.
+		corners[c] = world->ortho.view[world->cameraIndex].miniTilePositionToScreenPixel(getBoxCorner(minBound, maxBound, c), worldCenter);
+	}
+	BOX_LINE(0, 1);
+	BOX_LINE(2, 3);
+	BOX_LINE(4, 5);
+	BOX_LINE(6, 7);
+	BOX_LINE(0, 2);
+	BOX_LINE(1, 3);
+	BOX_LINE(4, 6);
+	BOX_LINE(5, 7);
+	BOX_LINE(0, 4);
+	BOX_LINE(1, 5);
+	BOX_LINE(2, 6);
+	BOX_LINE(3, 7);
+}
+
+void spriteWorld_debug_octrees(SpriteWorld& world, AlignedImageRgbaU8& colorTarget) {
+	MUST_EXIST(world, spriteWorld_debug_octrees);
+	IVector2D worldCenter = world->findWorldCenter(colorTarget);
+	IRect seenRegion = IRect(-worldCenter.x, -worldCenter.y, image_getWidth(colorTarget), image_getHeight(colorTarget));
+	OcTreeFilter orthoCullingFilter = [&world, &worldCenter, &seenRegion, &colorTarget](const IVector3D& minBound, const IVector3D& maxBound){
+		debugDrawBound(world, worldCenter, colorTarget, ColorRgbaI32(100, 100, 100, 255), minBound, maxBound);
+		return orthoCullingTest(world->ortho.view[world->cameraIndex], minBound, maxBound, seenRegion);
+	};
+	world->passiveSprites.map(orthoCullingFilter, [&world, &worldCenter, &colorTarget](SpriteInstance& sprite, const IVector3D origin, const IVector3D minBound, const IVector3D maxBound){
+		debugDrawBound(world, worldCenter, colorTarget, ColorRgbaI32(0, 255, 0, 255), minBound, maxBound);
+	});
+	world->passiveModels.map(orthoCullingFilter, [&world, &worldCenter, &colorTarget](ModelInstance& model, const IVector3D origin, const IVector3D minBound, const IVector3D maxBound){
+		debugDrawBound(world, worldCenter, colorTarget, ColorRgbaI32(0, 0, 255, 255), minBound, maxBound);
+	});
+}
+
 IVector3D spriteWorld_findGroundAtPixel(SpriteWorld& world, const AlignedImageRgbaU8& colorBuffer, const IVector2D& pixelLocation) {
 IVector3D spriteWorld_findGroundAtPixel(SpriteWorld& world, const AlignedImageRgbaU8& colorBuffer, const IVector2D& pixelLocation) {
 	MUST_EXIST(world, spriteWorld_findGroundAtPixel);
 	MUST_EXIST(world, spriteWorld_findGroundAtPixel);
 	return world->ortho.pixelToMiniPosition(pixelLocation, world->cameraIndex, world->findWorldCenter(colorBuffer));
 	return world->ortho.pixelToMiniPosition(pixelLocation, world->cameraIndex, world->findWorldCenter(colorBuffer));

+ 4 - 0
Source/SDK/SpriteEngine/spriteAPI.h

@@ -73,8 +73,12 @@ void spriteWorld_createTemporary_directedLight(SpriteWorld& world, const FVector
 
 
 void spriteWorld_clearTemporary(SpriteWorld& world);
 void spriteWorld_clearTemporary(SpriteWorld& world);
 
 
+// Draw the world using the current camera at the center of colorTarget
 void spriteWorld_draw(SpriteWorld& world, AlignedImageRgbaU8& colorTarget);
 void spriteWorld_draw(SpriteWorld& world, AlignedImageRgbaU8& colorTarget);
 
 
+// Draw debug information
+void spriteWorld_debug_octrees(SpriteWorld& world, AlignedImageRgbaU8& colorTarget);
+
 // The result is an approximation in mini-tile units.
 // The result is an approximation in mini-tile units.
 //   The 3D system does not align with screen pixels for less than whole tile units.
 //   The 3D system does not align with screen pixels for less than whole tile units.
 IVector3D spriteWorld_findGroundAtPixel(SpriteWorld& world, const AlignedImageRgbaU8& colorBuffer, const IVector2D& pixelLocation);
 IVector3D spriteWorld_findGroundAtPixel(SpriteWorld& world, const AlignedImageRgbaU8& colorBuffer, const IVector2D& pixelLocation);