Tile-based 2D viewport/camera - c++

This isn't so much a question as it is an 'anti-tunnel-vision' check.
I'm trying to get a camera/viewport working in a roguelike, but I'm not sure I'm doing things correctly.
Here's the code I've got so far:
void Map::moveCamera(int targetx,int targety) {
//size of the map portion shown on-screen
int CAMERA_WIDTH = 80;
int CAMERA_HEIGHT = 43;
int camera_x = 0;
int camera_y = 0;
//new camera coordinates (top-left corner of the screen relative to the map)
int x = targetx - CAMERA_WIDTH / 2; //coordinates so that the target is at the center of the screen
int y = targety - CAMERA_HEIGHT / 2;
//make sure the camera doesn't see outside the map
if (x < 0){
x = 0;
}
if (y < 0){
y = 0;
}
if (x > map_width - CAMERA_WIDTH - 1) {
x = map_width - CAMERA_WIDTH - 1;
}
if (y > map_height - CAMERA_HEIGHT - 1) {
y = map_height - CAMERA_HEIGHT - 1;
if (x != camera_x or y != camera_y) {
computeFov();
}
camera_x = x;
camera_y = y;
}
}
Now, when I change the size of the map, the camera is stuck way up in the corner and I can't see the map!
Can anyone point me in the right direction?

Related

Large height map interpolation

I have a vector<vector<double>> heightmap that is dynamically loaded from a CSV file of GPS data to be around 4000x4000. However, only provides 140,799 points.
It produces a greyscale map as shown bellow:
I wish to interpolate the heights between all the points to generate a height map of the area.
The below code finds all known points will look in a 10m radius of the point to find any other known points. If another point is found then it will linearly interpolate between the 2 points. Interpolated points are defined by - height and unset values are defined as -1337.
This approach is incredibly slow I am sure there are better ways to achieve this.
bool run_interp = true;
bool interp_interp = false;
int counter = 0;
while (run_interp)
{
for (auto x = 0; x < map.size(); x++)
{
for (auto y = 0; y < map.at(x).size(); y++)
{
const auto height = map.at(x).at(y);
if (height == -1337) continue;
if (!interp_interp && height < 0) continue;
//Look in a 10m radius of a known value to see if there
//Is another known value to linearly interp between
//Set height to a negative if it has been interped
const int radius = (1 / resolution) * 10;
for (auto rxi = 0; rxi < radius * 2; rxi++)
{
//since we want to expand outwards
const int rx = x + ((rxi % 2 == 0) ? rxi / 2 : -(rxi - 1) / 2);
if (rx < 0 || rx >= map.size()) continue;
for (auto ryi = 0; ryi < radius * 2; ryi++)
{
const int ry = y + ((rxi % 2 == 0) ? rxi / 2 : -(rxi - 1) / 2);
if (ry < 0 || ry >= map.at(x).size()) continue;
const auto new_height = map.at(rx).at(ry);
if (new_height == -1337) continue;
//First go around we don't want to interp
//Interps
if (!interp_interp && new_height < 0) continue;
//We have found a known point within 10m
const auto delta = new_height - height;
const auto distance = sqrt((rx- x) * (rx - x)
+ (ry - y) * (ry - y));
const auto angle = atan2(ry - y, rx - x);
const auto ratio = delta / distance;
//Backtrack from found point until we get to know point
for (auto radi = 0; radi < distance; radi++)
{
const auto new_x = static_cast<int>(x + radi * cos(angle));
const auto new_y = static_cast<int>(y + radi * sin(angle));
if (new_x < 0 || new_x >= map.size()) continue;
if (new_y < 0 || new_y >= map.at(new_x).size()) continue;
const auto interp_height = map.at(new_x).at(new_y);
//If it is a known height don't interp it
if (interp_height > 0)
continue;
counter++;
set_height(new_x, new_y, -interp_height);
}
}
}
}
std::cout << x << " " << counter << std::endl;;
}
if (interp_interp)
run_interp = false;
interp_interp = true;
}
set_height(const int x, const int y, const double height)
{
//First time data being set
if (map.at(x).at(y) == -1337)
{
map.at(x).at(y) = height;
}
else // Data set already so average it
{
//While this isn't technically correct and weights
//Later data significantly more favourablily
//It should be fine
//TODO: fix it.
map.at(x).at(y) += height;
map.at(x).at(y) /= 2;
}
}
If you put the points into a kd-tree, it will be much faster to find the closest point (O(nlogn)).
I'm not sure that will solve all your issues, but it is a start.

How to repair the spacing between blocks when I rotate them?

Hello I'm currently trying to rotate blocks that are within a square. But when I start to rotate them it starts to create weird spaces between blocks that I don't want. Could you help me to fix the problem of spaces beetween blocks? Here are some code and screenshots how does it look.
https://imgur.com/a/BLuO7FF
I have already checked if all angles and radiuses are calculated correctly and I don't see any problem there.
World.h
#pragma once
#include <SFML/Graphics.hpp>
class World
{
public:
World(sf::Vector2f Wpos);
float AngleToRadian(int angle);
void RotateWorld();
void draw(sf::RenderWindow &window);
sf::Texture tx;
sf::Sprite** Block;
sf::Vector2f Pos;
sf::Vector2i Size;
float** radius;
float** angle;
};
World.cpp
#include "World.h"
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cmath>
#define PI 3.14159
World::World(sf::Vector2f Wpos)
{
Pos = Wpos;
Size = sf::Vector2i(10, 10);
Block = new sf::Sprite*[Size.y];
radius = new float*[Size.y];
angle = new float*[Size.y];
for (int i = 0; i < Size.y; i++)
{
Block[i] = new sf::Sprite[Size.x];
radius[i] = new float[Size.x];
angle[i] = new float[Size.x];
}
tx.loadFromFile("Img/Block.png");
sf::Vector2i off(Size.x * tx.getSize().x / 2, Size.y * tx.getSize().y / 2); //tx size is 32px x 32px
for (int y = 0; y < Size.y; y++)
{
for (int x = 0; x < Size.x; x++)
{
Block[y][x].setTexture(tx);
Block[y][x].setOrigin(tx.getSize().x / 2, tx.getSize().y / 2);
Block[y][x].setPosition(x*tx.getSize().x + Wpos.x - off.x + Block[y][x].getOrigin().x, y*tx.getSize().y + Wpos.y - off.y + Block[y][x].getOrigin().y);
radius[y][x] = sqrt(pow(Pos.x - Block[y][x].getPosition().x, 2) + pow(Pos.y - Block[y][x].getPosition().y, 2));
angle[y][x] = (atan2(Block[y][x].getPosition().y - Pos.y, Block[y][x].getPosition().x - Pos.x) * 180.0) / PI;
if ((atan2(Block[y][x].getPosition().y - Pos.y, Block[y][x].getPosition().x - Pos.x) * 180.0) / PI < 0)
{
angle[y][x] += 360;
}
//angle[y][x] = round(angle[y][x]);
/*radius[y][x] = round(radius[y][x]);*/
}
}
}
void World::RotateWorld()
{
float dx = 0, dy = 0;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::E))
{
for (int y = 0; y < Size.y; y++)
{
for (int x = 0; x < Size.x; x++)
{
Block[y][x].rotate(1);
if (angle[y][x] >= 360)
{
angle[y][x] = 0;
}
angle[y][x]++;
dx = cos(AngleToRadian(angle[y][x])) * radius[y][x];
dy = sin(AngleToRadian(angle[y][x])) * radius[y][x];
Block[y][x].setPosition(Pos.x + dx, Pos.y + dy);
}
}
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
{
for (int y = 0; y < Size.y; y++)
{
for (int x = 0; x < Size.x; x++)
{
Block[y][x].rotate(-1);
if (angle[y][x] >= 360)
{
angle[y][x] = 0;
}
angle[y][x]--;
dx = cos(AngleToRadian(angle[y][x])) * radius[y][x];
dy = sin(AngleToRadian(angle[y][x])) * radius[y][x];
Block[y][x].setPosition(Pos.x + dx, Pos.y + dy);
}
}
}
}
I expected it to rotate withouth any spaces between. I would be really thankfull if someone would help me.
I would try with setting the origin of the sf::Sprite using it's getGlobalBounds() method instead of the sf::Texture size getter.
The difference seems minor and something like that might be the case.
Block[y][x].setTexture(tx);
Block[y][x].setOrigin(Block[y][x].getGlobalBouds().width / 2, Block[y][x].getGlobalBouds().height / 2);
Block[y][x].setPosition(x*Block[y][x].getGlobalBouds().width + Wpos.x - off.x + Block[y][x].getOrigin().x, y*Block[y][x].getGlobalBouds().height + Wpos.y - off.y + Block[y][x].getOrigin().y);

How to render an AABB while rotating

Hello I'm new to C++ SFML. I'm supposed to draw some rectangles and render their AABB while rotating and I want to detect if the dimensions set for them intersect another rotating AABB rectangle. Here is what I use to detect them.
Is it enough to check it that way if theyre rotating? would i need to use stuff like the separating axis theorem? or is there a way to not need to use that if its just an AABB than an OBB
#define RECT 5
sf::RectangleShape Rect[RECT];
Rect[0].setSize(sf::Vector2f(50.0f, 50.0f));
Rect[1].setSize(sf::Vector2f(50.0f, 100.0f));
Rect[2].setSize(sf::Vector2f(60.0f, 80.0f));
Rect[3].setSize(sf::Vector2f(100.0f, 60.0f));
Rect[4].setSize(sf::Vector2f(30.0f, 250.0f));
sf::Vector2f MinPoint[RECT];
sf::Vector2f MaxPoint[RECT];
for (int x = 0; x < RECT; x++)
{
//Starting Position
Rect[x].setOrigin(Rect[x].getSize().x / 2, Rect[x].getSize().y / 2);
xpos += 150;
Rect[x].setPosition(xpos, ypos);
colcount++;
if (colcount == 3)
{
xpos = 0;
ypos += 200;
colcount = 0;
}
Rect[x].setFillColor(sf::Color::Red);
}
while (window.isOpen())
{
window.clear(sf::Color::Black);
//Drawing Shapes
for (int x = 0; x < RECT; x++)
{
window.draw(Rect[x]);
}
Rect[0].rotate(90*3.14/180);
Rect[1].rotate(12 * 3.14 / 180);
Rect[2].rotate(10 * 3.14 / 180);
Rect[3].rotate(180 * 3.14 / 180);
Rect[4].rotate(360 * 3.14 / 180);
for (int i = 0; i < RECT; i++)
{
MinPoint[i].x = Rect[i].getPosition().x - (Rect[i].getSize().x / 2);
MaxPoint[i].x = Rect[i].getPosition().x + (Rect[i].getSize().x / 2);
MinPoint[i].y = Rect[i].getPosition().y - (Rect[i].getSize().y / 2);
MaxPoint[i].y = Rect[i].getPosition().y + (Rect[i].getSize().y / 2);
}
//Collision Detection
for (int i = 0; i < RECT; i++)
{
for (int j = i + 1; j < RECT; j++)
{
if (i != j)
{
if (MaxPoint[i].x >= MinPoint[j].x && MaxPoint[j].x >= MinPoint[i].x && MaxPoint[i].y >= MinPoint[j].y && MaxPoint[j].y >= MinPoint[i].y)
{
Rect[i].setFillColor(sf::Color::Green);
Rect[j].setFillColor(sf::Color::Green);
}
}
}
}
Apparently all I needed to do was make another set of transparent rectangles with outlines that were set at the same position as my rotating rectangle boxes then set their sizes to getGlobalBounds of my rotating rectangles. the collision check would then instead be put under these transparent bounding boxes instead of the rotating rectangle itself.
#define RECT 5
sf::RectangleShape Rect[RECT];
sf::RectangleShape AABB[RECT];
Rect[0].setSize(sf::Vector2f(50.0f, 50.0f));
Rect[1].setSize(sf::Vector2f(50.0f, 100.0f));
Rect[2].setSize(sf::Vector2f(60.0f, 80.0f));
Rect[3].setSize(sf::Vector2f(100.0f, 60.0f));
Rect[4].setSize(sf::Vector2f(30.0f, 250.0f));
sf::Vector2f MinPoint[RECT];
sf::Vector2f MaxPoint[RECT];
for (int x = 0; x < RECT; x++)
{
//Starting Position
Rect[x].setOrigin(Rect[x].getSize().x / 2, Rect[x].getSize().y / 2);
AABB[x].setOrigin(AABB[x].getSize().x / 2, AABB[x].getSize().y / 2);
xpos += 150;
Rect[x].setPosition(xpos, ypos);
AABB[x].setSize(sf::Vector2f(Rect[x].getGlobalBounds().width, Rect[x].getGlobalBounds().height));
AABB[x].setPosition(Rect[x].getPosition().x, Rect[x].getPosition().y);
colcount++;
if (colcount == 3)
{
xpos = 0;
ypos += 200;
colcount = 0;
}
Rect[x].setFillColor(sf::Color::Red);
AABB[x].setFillColor(sf::Color::Transparent);
AABB[x].setOutlineThickness(1);
AABB[x].setOutlineColor(sf::Color::White);
}
while (window.isOpen())
{
window.clear(sf::Color::Black);
//Drawing Shapes
for (int x = 0; x < RECT; x++)
{
window.draw(Rect[x]);
window.draw(AABB[x]);
}
//Rotation
Rect[0].rotate(1);
Rect[1].rotate(45);
Rect[2].rotate(11.25);
Rect[3].rotate(5.625);
Rect[4].rotate(22.5);
for (int i = 0; i < RECT; i++)
{
MinPoint[i].x = AABB[i].getPosition().x - (AABB[i].getSize().x / 2);
MaxPoint[i].x = AABB[i].getPosition().x + (AABB[i].getSize().x / 2);
MinPoint[i].y = AABB[i].getPosition().y - (AABB[i].getSize().y / 2);
MaxPoint[i].y = AABB[i].getPosition().y + (AABB[i].getSize().y / 2);
AABB[i].setOrigin(AABB[i].getSize().x / 2, AABB[i].getSize().y / 2);
AABB[i].setSize(sf::Vector2f(Rect[i].getGlobalBounds().width, Rect[i].getGlobalBounds().height));
AABB[i].setPosition(Rect[i].getPosition().x, Rect[i].getPosition().y);
}
//Collision Detection
for (int i = 0; i < RECT; i++)
{
for (int j = i + 1; j < RECT; j++)
{
if (i != j)
{
if (MaxPoint[i].x >= MinPoint[j].x && MaxPoint[j].x >= MinPoint[i].x && MaxPoint[i].y >= MinPoint[j].y && MaxPoint[j].y >= MinPoint[i].y)
{
Rect[i].setFillColor(sf::Color::Green);
Rect[j].setFillColor(sf::Color::Green);
AABB[i].setOutlineColor(sf::Color::Blue);
AABB[j].setOutlineColor(sf::Color::Blue);
}
}
}
}

Rotating image not working

I'm trying to rotate an image using openFrameworks, but I have a problem. My rotated image is red instead of its original color.
void testApp::setup(){
image.loadImage("abe2.jpg");
rotatedImage.allocate(image.width, image.height, OF_IMAGE_COLOR);
imageCenterX = image.getWidth() / 2;
imageCenterY = image.getHeight() / 2;
w = image.getWidth();
h = image.getHeight();
int degrees = 180;
float radians = (degrees*(PI / 180));
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int index = image.getPixelsRef().getPixelIndex(x, y);
int newX = (cos(radians) * (x - imageCenterX) - sin(radians) * (y - imageCenterY) + imageCenterX);
int newY = (sin(radians) * (x - imageCenterX) + cos(radians) * (y - imageCenterY) + imageCenterY);
int newIndex = rotatedImage.getPixelsRef().getPixelIndex(newX, newY);
rotatedImage.getPixelsRef()[newIndex] = image.getPixelsRef()[index];
}
}
rotatedImage.update();
}
void testApp::update(){
}
void testApp::draw(){
image.draw(0,0);
rotatedImage.draw(0,400);
}
Can someone tell me what I am doing wrong?
If your image has three color components (Red, Green, Blue), you need to transform all three of those. The following should do the trick:
rotatedImage.getPixelsRef()[newIndex] = image.getPixelsRef()[index];
rotatedImage.getPixelsRef()[newIndex+1] = image.getPixelsRef()[index+1];
rotatedImage.getPixelsRef()[newIndex+2] = image.getPixelsRef()[index+2];

C++ triangle rasterization

I'm trying to fix this triangle rasterizer, but cannot make it work correctly. For some reason it only draws half of the triangles.
void DrawTriangle(Point2D p0, Point2D p1, Point2D p2)
{
Point2D Top, Middle, Bottom;
bool MiddleIsLeft;
if (p0.y < p1.y) // case: 1, 2, 5
{
if (p0.y < p2.y) // case: 1, 2
{
if (p1.y < p2.y) // case: 1
{
Top = p0;
Middle = p1;
Bottom = p2;
MiddleIsLeft = true;
}
else // case: 2
{
Top = p0;
Middle = p2;
Bottom = p1;
MiddleIsLeft = false;
}
}
else // case: 5
{
Top = p2;
Middle = p0;
Bottom = p1;
MiddleIsLeft = true;
}
}
else // case: 3, 4, 6
{
if (p0.y < p2.y) // case: 4
{
Top = p1;
Middle = p0;
Bottom = p2;
MiddleIsLeft = false;
}
else // case: 3, 6
{
if (p1.y < p2.y) // case: 3
{
Top = p1;
Middle = p2;
Bottom = p0;
MiddleIsLeft = true;
}
else // case 6
{
Top = p2;
Middle = p1;
Bottom = p0;
MiddleIsLeft = false;
}
}
}
float xLeft, xRight;
xLeft = xRight = Top.x;
float mLeft, mRight;
// Region 1
if(MiddleIsLeft)
{
mLeft = (Top.x - Middle.x) / (Top.y - Middle.y);
mRight = (Top.x - Bottom.x) / (Top.y - Bottom.y);
}
else
{
mLeft = (Top.x - Bottom.x) / (Top.y - Bottom.y);
mRight = (Middle.x - Top.x) / (Middle.y - Top.y);
}
int finalY;
float Tleft, Tright;
for (int y = ceil(Top.y); y < (int)Middle.y; y++)
{
Tleft=float(Top.y-y)/(Top.y-Middle.y);
Tright=float(Top.y-y)/(Top.y-Bottom.y);
for (int x = ceil(xLeft); x <= ceil(xRight) - 1 ; x++)
{
FrameBuffer::SetPixel(x, y, p0.r,p0.g,p0.b);
}
xLeft += mLeft;
xRight += mRight;
finalY = y;
}
// Region 2
if (MiddleIsLeft)
{
mLeft = (Bottom.x - Middle.x) / (Bottom.y - Middle.y);
}
else
{
mRight = (Middle.x - Bottom.x) / (Middle.y - Bottom.y);
}
for (int y = Middle.y; y <= ceil(Bottom.y) - 1; y++)
{
Tleft=float(Bottom.y-y)/(Bottom.y-Middle.y);
Tright=float(Top.y-y)/(Top.y-Bottom.y);
for (int x = ceil(xLeft); x <= ceil(xRight) - 1; x++)
{
FrameBuffer::SetPixel(x, y, p0.r,p0.g,p0.b);
}
xLeft += mLeft;
xRight += mRight;
}
}
Here is what happens when I use it to draw shapes.
When I disable the second region, all those weird triangles disappear.
The wireframe mode works perfect, so this eliminates all the other possibilities other than the triangle rasterizer.
I kind of got lost in your implementation, but here's what I do (I have a slightly more complex version for arbitrary convex polygons, not just triangles) and I think apart from the Bresenham's algorithm it's very simple (actually the algorithm is simple too):
#include <stddef.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#define SCREEN_HEIGHT 22
#define SCREEN_WIDTH 78
// Simulated frame buffer
char Screen[SCREEN_HEIGHT][SCREEN_WIDTH];
void SetPixel(long x, long y, char color)
{
if ((x < 0) || (x >= SCREEN_WIDTH) ||
(y < 0) || (y >= SCREEN_HEIGHT))
{
return;
}
Screen[y][x] = color;
}
void Visualize(void)
{
long x, y;
for (y = 0; y < SCREEN_HEIGHT; y++)
{
for (x = 0; x < SCREEN_WIDTH; x++)
{
printf("%c", Screen[y][x]);
}
printf("\n");
}
}
typedef struct
{
long x, y;
unsigned char color;
} Point2D;
// min X and max X for every horizontal line within the triangle
long ContourX[SCREEN_HEIGHT][2];
#define ABS(x) ((x >= 0) ? x : -x)
// Scans a side of a triangle setting min X and max X in ContourX[][]
// (using the Bresenham's line drawing algorithm).
void ScanLine(long x1, long y1, long x2, long y2)
{
long sx, sy, dx1, dy1, dx2, dy2, x, y, m, n, k, cnt;
sx = x2 - x1;
sy = y2 - y1;
if (sx > 0) dx1 = 1;
else if (sx < 0) dx1 = -1;
else dx1 = 0;
if (sy > 0) dy1 = 1;
else if (sy < 0) dy1 = -1;
else dy1 = 0;
m = ABS(sx);
n = ABS(sy);
dx2 = dx1;
dy2 = 0;
if (m < n)
{
m = ABS(sy);
n = ABS(sx);
dx2 = 0;
dy2 = dy1;
}
x = x1; y = y1;
cnt = m + 1;
k = n / 2;
while (cnt--)
{
if ((y >= 0) && (y < SCREEN_HEIGHT))
{
if (x < ContourX[y][0]) ContourX[y][0] = x;
if (x > ContourX[y][1]) ContourX[y][1] = x;
}
k += n;
if (k < m)
{
x += dx2;
y += dy2;
}
else
{
k -= m;
x += dx1;
y += dy1;
}
}
}
void DrawTriangle(Point2D p0, Point2D p1, Point2D p2)
{
int y;
for (y = 0; y < SCREEN_HEIGHT; y++)
{
ContourX[y][0] = LONG_MAX; // min X
ContourX[y][1] = LONG_MIN; // max X
}
ScanLine(p0.x, p0.y, p1.x, p1.y);
ScanLine(p1.x, p1.y, p2.x, p2.y);
ScanLine(p2.x, p2.y, p0.x, p0.y);
for (y = 0; y < SCREEN_HEIGHT; y++)
{
if (ContourX[y][1] >= ContourX[y][0])
{
long x = ContourX[y][0];
long len = 1 + ContourX[y][1] - ContourX[y][0];
// Can draw a horizontal line instead of individual pixels here
while (len--)
{
SetPixel(x++, y, p0.color);
}
}
}
}
int main(void)
{
Point2D p0, p1, p2;
// clear the screen
memset(Screen, ' ', sizeof(Screen));
// generate random triangle coordinates
srand((unsigned)time(NULL));
p0.x = rand() % SCREEN_WIDTH;
p0.y = rand() % SCREEN_HEIGHT;
p1.x = rand() % SCREEN_WIDTH;
p1.y = rand() % SCREEN_HEIGHT;
p2.x = rand() % SCREEN_WIDTH;
p2.y = rand() % SCREEN_HEIGHT;
// draw the triangle
p0.color = '1';
DrawTriangle(p0, p1, p2);
// also draw the triangle's vertices
SetPixel(p0.x, p0.y, '*');
SetPixel(p1.x, p1.y, '*');
SetPixel(p2.x, p2.y, '*');
Visualize();
return 0;
}
Output:
*111111
1111111111111
111111111111111111
1111111111111111111111
111111111111111111111111111
11111111111111111111111111111111
111111111111111111111111111111111111
11111111111111111111111111111111111111111
111111111111111111111111111111111111111*
11111111111111111111111111111111111
1111111111111111111111111111111
111111111111111111111111111
11111111111111111111111
1111111111111111111
11111111111111
11111111111
1111111
1*
The original code will only work properly with triangles that have counter-clockwise winding because of the if-else statements on top that determines whether middle is left or right. It could be that the triangles which aren't drawing have the wrong winding.
This stack overflow shows how to Determine winding of a 2D triangles after triangulation
The original code is fast because it doesn't save the points of the line in a temporary memory buffer. Seems a bit over-complicated even given that, but that's another problem.
The following code is in your implementation:
if (p0.y < p1.y) // case: 1, 2, 5
{
if (p0.y < p2.y) // case: 1, 2
{
if (p1.y < p2.y) // case: 1
{
Top = p0;
Middle = p1;
Bottom = p2;
MiddleIsLeft = true;
}
else // case: 2
{
Top = p0;
Middle = p2;
Bottom = p1;
MiddleIsLeft = false;
}
}
This else statement means that p2.y (or Middle) can equal p1.y (or Bottom). If this is true, then when region 2 runs
if (MiddleIsLeft)
{
mLeft = (Bottom.x - Middle.x) / (Bottom.y - Middle.y);
}
else
{
mRight = (Middle.x - Bottom.x) / (Middle.y - Bottom.y);
}
That else line will commit division by zero, which is not possible.