Draw a line with a constant length by mouse direction - c++

As question says, I want to draw a line starting at X,Y position to, for example, 10 pixels on mouse direction... The function I already have draws a line between 2 points, but I can't figure how to do it with a constant lenght on mouse direction
Here is the function:
void D3DGraphics::DrawLine( int x1,int y1,int x2,int y2,int r,int g,int blu )
{
int dx = x2 - x1;
int dy = y2 - y1;
if( dy == 0 && dx == 0 )
{
PutPixel( x1,y1,r,g,blu );
}
else if( abs( dy ) > abs( dx ) )
{
if( dy < 0 )
{
int temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
float m = (float)dx / (float)dy;
float b = x1 - m*y1;
for( int y = y1; y <= y2; y = y + 1 )
{
int x = (int)(m*y + b + 0.5f);
PutPixel( x,y,r,g,blu );
}
}
else
{
if( dx < 0 )
{
int temp = x1;
x1 = x2;
x2 = temp;
temp = y1;
y1 = y2;
y2 = temp;
}
float m = (float)dy / (float)dx;
float b = y1 - m*x1;
for( int x = x1; x <= x2; x = x + 1 )
{
int y = (int)(m*x + b + 0.5f);
PutPixel( x,y,r,g,blu );
}
}
}
I also have a function that gets the mouse X and Y position on the screen (getmouseX(), getmouseY())

Direct3D has D3DXVECTOR2, D3DXVECTOR3, D3DXCOLOR and similar structures. You should probably use them. Or use typedef D3DXVECTOR2 Vec2; or something like that. Those structures come with mathematical functions, so using them makes sense. Oh, and they operate on floats.
Drawing one pixel at a time is a bad theme - it is slow. Also you can easily draw entire line in one call using IDirect3DDevice9->DrawPrimitive(D3DPT_LINELIST..)
Even if you don't want to use D3DX* structures, you should probably use strctures to store colors and coordinates:
Example:
struct Coord{
int x, y;
};
struct Color{
unsigned char a, b, g, r;
};
regarding your question.
typedef D3DXVECTOR2 Vec2;
....
Vec2 startPos = ...;
Vec2 endPos = getMousePos();
const float desiredLength = ...;//whatever you need here.
Vec2 diff = endPos - startPos; //should work. If it doesn't, use
//D3DXVec2Subtract(&diff, &endPos, &startPoss);
float currentLength = D3DXVec2Length(&diff);
if (currentLength != 0)
D3DXVec2Scale(&diff, &diff, desiredLength/currentLength);// diff *= desiredLength/currentLength
else
diff = Vec2(0.0f, 0.0f);
endPos = startPos + diff; //if it doesn't work, use D3DXVec2Add(&endPos, &startPos, &diff);
This way endPos will not be further than desiredLength than startPos. Unless startPos == endPos
P.S. If you REALLY want to draw the line yourself, you may want to research bresenham line drawing algorithm.

ratio = (length betweeen start position and mouse position)/10
x = startX+(mouseX-startX)/ratio
y = startY+(mouseY-startY)/ratio
I think its something like this

Related

Triangle rasterization DirectX & Win32 Gdi

I'm currently following Andre Lamothe's book Tricks of the Windows Game Programming Gurus and trying to write my own software renderer with Win32 GDI. However, I got stuck at the triangle rasterization part of the book where the author is using Bresenham's line algorithm. I managed to get the rasterization to work on DirectX, but not on Win32 GDI despite identical rendering code. Both renders a triangle but the DirectX one renders it correctly while the Win32 almost renders it correctly
Link to my code: https://pastebin.com/VwySmQXS
It could be worth mention that the DirectX version is written in c++, while my own is written in C. I wasn't able to get a good screenshot of the two triangles so here is a picture painted in paint of how they both look.
Left is DirectX (how I want it to look), right is Win32 GDI:
Am I missing something here? Both draw_triangle_2d are called with the same arguments.
static void draw_top_tri(struct render_buffer *buffer,
int x1, int y1,
int x2, int y2,
int x3, int y3,
float r, float g, float b, float a)
{
unsigned int color = vec4_to_uint(vec4_mul(Vec4(r, g, b, a), 255.0f));
// this function draws a triangle that has a flat top
float dx_right, // the dx/dy ratio of the right edge of line
dx_left, // the dx/dy ratio of the left edge of line
xs, xe, // the starting and ending points of the edges
height; // the height of the triangle
int temp_x, // used during sorting as temps
temp_y,
right, // used by clipping
left;
// destination address of next scanline
unsigned int *dest_addr = NULL;
// test order of x1 and x2
if(x2 < x1)
{
temp_x = x2;
x2 = x1;
x1 = temp_x;
} // end if swap
// compute delta's
height = (float)(y3 - y1);
dx_left = (x3 - x1) / height;
dx_right = (x3 - x2) / height;
// set starting points
xs = (float)x1;
xe = (float)x2 + (float)0.5;
// perform y clipping
if(y1 < MIN_CLIP_Y)
{
// compute new xs and ys
xs = xs + dx_left * (float)(-y1 + MIN_CLIP_Y);
xe = xe + dx_right * (float)(-y1 + MIN_CLIP_Y);
// reset y1
y1 = MIN_CLIP_Y;
} // end if top is off screen
if(y3 > MAX_CLIP_X)
y3 = MAX_CLIP_X;
// compute starting address in video memory
dest_addr = (unsigned int *)buffer->memory + y1 * buffer->width;
// test if x clipping is needed
if(x1 >= MIN_CLIP_X && x1 <= MAX_CLIP_X &&
x2 >= MIN_CLIP_X && x2 <= MAX_CLIP_X &&
x3 >= MIN_CLIP_X && x3 <= MAX_CLIP_X)
{
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
memset((unsigned int *)dest_addr + (unsigned int)xs,
color, (unsigned int)(xe - xs + 1) * 4);
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
} // end for
} // end if no x clipping needed
else
{
// clip x axis with slower version
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
// do x clip
left = (int)xs;
right = (int)xe;
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
// clip line
if(left < MIN_CLIP_X)
{
left = MIN_CLIP_X;
if(right < MIN_CLIP_X)
continue;
}
if(right > MAX_CLIP_X)
{
right = MAX_CLIP_X;
if(left > MAX_CLIP_X)
continue;
}
memset((unsigned int *)dest_addr + (unsigned int)left,
color, (unsigned int)(right - left + 1) * 4);
} // end for
} // end else x clipping needed
} // end Draw_Top_Tri
static void
draw_bottom_tri(struct render_buffer *buffer,
int x1, int y1,
int x2, int y2,
int x3, int y3,
float r, float g, float b, float a)
{
unsigned int color = vec4_to_uint(vec4_mul(Vec4(r, g, b, a), 255.0f));
// this function draws a triangle that has a flat bottom
float dx_right, // the dx/dy ratio of the right edge of line
dx_left, // the dx/dy ratio of the left edge of line
xs, xe, // the starting and ending points of the edges
height; // the height of the triangle
int temp_x, // used during sorting as temps
temp_y,
right, // used by clipping
left;
// destination address of next scanline
unsigned int *dest_addr;
// test order of x1 and x2
if(x3 < x2)
{
temp_x = x2;
x2 = x3;
x3 = temp_x;
} // end if swap
// compute delta's
height = (float)(y3 - y1);
dx_left = (x2 - x1) / height;
dx_right = (x3 - x1) / height;
// set starting points
xs = (float)x1;
xe = (float)x1; // +(float)0.5;
// perform y clipping
if(y1 < MIN_CLIP_Y)
{
// compute new xs and ys
xs = xs + dx_left * (float)(-y1 + MIN_CLIP_Y);
xe = xe + dx_right * (float)(-y1 + MIN_CLIP_Y);
// reset y1
y1 = MIN_CLIP_Y;
} // end if top is off screen
if(y3 > MAX_CLIP_X)
y3 = MAX_CLIP_X;
// compute starting address in video memory
dest_addr = (unsigned int *)buffer->memory + y1 * buffer->width;
// test if x clipping is needed
if(x1 >= MIN_CLIP_X && x1 <= MAX_CLIP_X &&
x2 >= MIN_CLIP_X && x2 <= MAX_CLIP_X &&
x3 >= MIN_CLIP_X && x3 <= MAX_CLIP_X)
{
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
memset((unsigned int *)dest_addr + (unsigned int)xs,
color, (unsigned int)(xe - xs + 1) * 4);
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
} // end for
} // end if no x clipping needed
else
{
// clip x axis with slower version
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
// do x clip
left = (int)xs;
right = (int)xe;
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
// clip line
if(left < MIN_CLIP_X)
{
left = MIN_CLIP_X;
if(right < MIN_CLIP_X)
continue;
}
if(right > MAX_CLIP_X)
{
right = MAX_CLIP_X;
if(left > MAX_CLIP_X)
continue;
}
memset((unsigned int *)dest_addr + (unsigned int)left,
color, (unsigned int)(right - left + 1) * 4);
} // end for
} // end else x clipping needed
} // end Draw_Bottom_Tri}
ENGINE_CORE_EXPORT void
draw_triangle_2d(struct render_buffer *buffer,
int x1, int y1,
int x2, int y2,
int x3, int y3,
float r, float g, float b, float a)
{
// this function draws a triangle on the destination buffer
// it decomposes all triangles into a pair of flat top, flat bottom
int temp_x, // used for sorting
temp_y,
new_x;
// test for h lines and v lines
if((x1 == x2 && x2 == x3) || (y1 == y2 && y2 == y3))
return;
// sort p1,p2,p3 in ascending y order
if(y2 < y1)
{
temp_x = x2;
temp_y = y2;
x2 = x1;
y2 = y1;
x1 = temp_x;
y1 = temp_y;
} // end if
// now we know that p1 and p2 are in order
if(y3 < y1)
{
temp_x = x3;
temp_y = y3;
x3 = x1;
y3 = y1;
x1 = temp_x;
y1 = temp_y;
} // end if
// finally test y3 against y2
if(y3 < y2)
{
temp_x = x3;
temp_y = y3;
x3 = x2;
y3 = y2;
x2 = temp_x;
y2 = temp_y;
} // end if
// do trivial rejection tests for clipping
if(y3 < MIN_CLIP_Y || y1 > MAX_CLIP_X ||
(x1 < MIN_CLIP_X && x2 < MIN_CLIP_X && x3 < MIN_CLIP_X) ||
(x1 > MAX_CLIP_X && x2 > MAX_CLIP_X && x3 > MAX_CLIP_X))
return;
// test if top of triangle is flat
if(y1 == y2)
{
draw_top_tri(buffer, x1, y1, x2, y2, x3, y3, r, g, b, a);
} // end if
else
if(y2 == y3)
{
draw_bottom_tri(buffer, x1, y1, x2, y2, x3, y3, r, g, b, a);
} // end if bottom is flat
else
{
// general triangle that's needs to be broken up along long edge
new_x = x1 + (int)(0.5 + (float)(y2 - y1) * (float)(x3 - x1) / (float)(y3 - y1));
// draw each sub-triangle
draw_bottom_tri(buffer, x1, y1, new_x, y2, x2, y2, r, g, b, a);
draw_top_tri(buffer, x2, y2, new_x, y2, x3, y3, r, g, b, a);
} // end else
} // end Draw_Triangle_2D

Delaunay triangulation : too many triangles

I'm trying to implement the Delaunay triangulation in C++. Currently it's working, but I'm not getting the correct amount of triangles.
I try it with 4 points in a square pattern : (0,0), (1,0), (0,1), (1,1).
Here's the algorithm I use :
std::vector<Triangle> Delaunay::triangulate(std::vector<Vec2f> &vertices) {
// Determinate the super triangle
float minX = vertices[0].getX();
float minY = vertices[0].getY();
float maxX = minX;
float maxY = minY;
for(std::size_t i = 0; i < vertices.size(); ++i) {
if (vertices[i].getX() < minX) minX = vertices[i].getX();
if (vertices[i].getY() < minY) minY = vertices[i].getY();
if (vertices[i].getX() > maxX) maxX = vertices[i].getX();
if (vertices[i].getY() > maxY) maxY = vertices[i].getY();
}
float dx = maxX - minX;
float dy = maxY - minY;
float deltaMax = std::max(dx, dy);
float midx = (minX + maxX) / 2.f;
float midy = (minY + maxY) / 2.f;
Vec2f p1(midx - 20 * deltaMax, midy - deltaMax);
Vec2f p2(midx, midy + 20 * deltaMax);
Vec2f p3(midx + 20 * deltaMax, midy - deltaMax);
// Add the super triangle vertices to the end of the vertex list
vertices.push_back(p1);
vertices.push_back(p2);
vertices.push_back(p3);
// Add the super triangle to the triangle list
std::vector<Triangle> triangleList = {Triangle(p1, p2, p3)};
// For each point in the vertex list
for(auto point = begin(vertices); point != end(vertices); point++)
{
// Initialize the edges buffer
std::vector<Edge> edgesBuff;
// For each triangles currently in the triangle list
for(auto triangle = begin(triangleList); triangle != end(triangleList);)
{
if(triangle->inCircumCircle(*point))
{
Edge tmp[3] = {triangle->getE1(), triangle->getE2(), triangle->getE3()};
edgesBuff.insert(end(edgesBuff), tmp, tmp + 3);
triangle = triangleList.erase(triangle);
}
else
{
triangle++;
}
}
// Delete all doubly specified edges from the edge buffer
// Black magic by https://github.com/MechaRage
auto ite = begin(edgesBuff), last = end(edgesBuff);
while(ite != last) {
// Search for at least one duplicate of the current element
auto twin = std::find(ite + 1, last, *ite);
if(twin != last)
// If one is found, push them all to the end.
last = std::partition(ite, last, [&ite](auto const &o){ return !(o == *ite); });
else
++ite;
}
// Remove all the duplicates, which have been shoved past "last".
edgesBuff.erase(last, end(edgesBuff));
// Add the triangle to the list
for(auto edge = begin(edgesBuff); edge != end(edgesBuff); edge++)
triangleList.push_back(Triangle(edge->getP1(), edge->getP2(), *point));
}
// Remove any triangles from the triangle list that use the supertriangle vertices
triangleList.erase(std::remove_if(begin(triangleList), end(triangleList), [p1, p2, p3](auto t){
return t.containsVertex(p1) || t.containsVertex(p2) || t.containsVertex(p3);
}), end(triangleList));
return triangleList;
}
And here's what I obtain :
Triangle:
Point x: 1 y: 0
Point x: 0 y: 0
Point x: 1 y: 1
Triangle:
Point x: 1 y: 0
Point x: 1 y: 1
Point x: 0 y: 1
Triangle:
Point x: 0 y: 0
Point x: 1 y: 1
Point x: 0 y: 1
While this would be the correct output :
Triangle:
Point x: 1 y: 0
Point x: 0 y: 0
Point x: 0 y: 1
Triangle:
Point x: 1 y: 0
Point x: 1 y: 1
Point x: 0 y: 1
I have no idea why there is a triangle with the (0, 0) and the (1, 1).
I need an outside eye to review the code and find out what's going wrong.
All the sources are on my Github repo. Feel free to fork it and to PR your code.
Thanks!
what about this implementation of Paul Bourke's Delaunay triangulation algorithm. Take a look at Triangulate() I have used this source many times without any complains
#include <iostream>
#include <stdlib.h> // for C qsort
#include <cmath>
#include <time.h> // for random
const int MaxVertices = 500;
const int MaxTriangles = 1000;
//const int n_MaxPoints = 10; // for the test programm
const double EPSILON = 0.000001;
struct ITRIANGLE{
int p1, p2, p3;
};
struct IEDGE{
int p1, p2;
};
struct XYZ{
double x, y, z;
};
int XYZCompare(const void *v1, const void *v2);
int Triangulate(int nv, XYZ pxyz[], ITRIANGLE v[], int &ntri);
int CircumCircle(double, double, double, double, double, double, double, double, double&, double&, double&);
using namespace std;
////////////////////////////////////////////////////////////////////////
// CircumCircle() :
// Return true if a point (xp,yp) is inside the circumcircle made up
// of the points (x1,y1), (x2,y2), (x3,y3)
// The circumcircle centre is returned in (xc,yc) and the radius r
// Note : A point on the edge is inside the circumcircle
////////////////////////////////////////////////////////////////////////
int CircumCircle(double xp, double yp, double x1, double y1, double x2,
double y2, double x3, double y3, double &xc, double &yc, double &r){
double m1, m2, mx1, mx2, my1, my2;
double dx, dy, rsqr, drsqr;
/* Check for coincident points */
if(abs(y1 - y2) < EPSILON && abs(y2 - y3) < EPSILON)
return(false);
if(abs(y2-y1) < EPSILON){
m2 = - (x3 - x2) / (y3 - y2);
mx2 = (x2 + x3) / 2.0;
my2 = (y2 + y3) / 2.0;
xc = (x2 + x1) / 2.0;
yc = m2 * (xc - mx2) + my2;
}else if(abs(y3 - y2) < EPSILON){
m1 = - (x2 - x1) / (y2 - y1);
mx1 = (x1 + x2) / 2.0;
my1 = (y1 + y2) / 2.0;
xc = (x3 + x2) / 2.0;
yc = m1 * (xc - mx1) + my1;
}else{
m1 = - (x2 - x1) / (y2 - y1);
m2 = - (x3 - x2) / (y3 - y2);
mx1 = (x1 + x2) / 2.0;
mx2 = (x2 + x3) / 2.0;
my1 = (y1 + y2) / 2.0;
my2 = (y2 + y3) / 2.0;
xc = (m1 * mx1 - m2 * mx2 + my2 - my1) / (m1 - m2);
yc = m1 * (xc - mx1) + my1;
}
dx = x2 - xc;
dy = y2 - yc;
rsqr = dx * dx + dy * dy;
r = sqrt(rsqr);
dx = xp - xc;
dy = yp - yc;
drsqr = dx * dx + dy * dy;
return((drsqr <= rsqr) ? true : false);
}
///////////////////////////////////////////////////////////////////////////////
// Triangulate() :
// Triangulation subroutine
// Takes as input NV vertices in array pxyz
// Returned is a list of ntri triangular faces in the array v
// These triangles are arranged in a consistent clockwise order.
// The triangle array 'v' should be malloced to 3 * nv
// The vertex array pxyz must be big enough to hold 3 more points
// The vertex array must be sorted in increasing x values say
//
// qsort(p,nv,sizeof(XYZ),XYZCompare);
///////////////////////////////////////////////////////////////////////////////
int Triangulate(int nv, XYZ pxyz[], ITRIANGLE v[], int &ntri){
int *complete = NULL;
IEDGE *edges = NULL;
IEDGE *p_EdgeTemp;
int nedge = 0;
int trimax, emax = 200;
int status = 0;
int inside;
int i, j, k;
double xp, yp, x1, y1, x2, y2, x3, y3, xc, yc, r;
double xmin, xmax, ymin, ymax, xmid, ymid;
double dx, dy, dmax;
/* Allocate memory for the completeness list, flag for each triangle */
trimax = 4 * nv;
complete = new int[trimax];
/* Allocate memory for the edge list */
edges = new IEDGE[emax];
/*
Find the maximum and minimum vertex bounds.
This is to allow calculation of the bounding triangle
*/
xmin = pxyz[0].x;
ymin = pxyz[0].y;
xmax = xmin;
ymax = ymin;
for(i = 1; i < nv; i++){
if (pxyz[i].x < xmin) xmin = pxyz[i].x;
if (pxyz[i].x > xmax) xmax = pxyz[i].x;
if (pxyz[i].y < ymin) ymin = pxyz[i].y;
if (pxyz[i].y > ymax) ymax = pxyz[i].y;
}
dx = xmax - xmin;
dy = ymax - ymin;
dmax = (dx > dy) ? dx : dy;
xmid = (xmax + xmin) / 2.0;
ymid = (ymax + ymin) / 2.0;
/*
Set up the supertriangle
his is a triangle which encompasses all the sample points.
The supertriangle coordinates are added to the end of the
vertex list. The supertriangle is the first triangle in
the triangle list.
*/
pxyz[nv+0].x = xmid - 20 * dmax;
pxyz[nv+0].y = ymid - dmax;
pxyz[nv+1].x = xmid;
pxyz[nv+1].y = ymid + 20 * dmax;
pxyz[nv+2].x = xmid + 20 * dmax;
pxyz[nv+2].y = ymid - dmax;
v[0].p1 = nv;
v[0].p2 = nv+1;
v[0].p3 = nv+2;
complete[0] = false;
ntri = 1;
/*
Include each point one at a time into the existing mesh
*/
for(i = 0; i < nv; i++){
xp = pxyz[i].x;
yp = pxyz[i].y;
nedge = 0;
/*
Set up the edge buffer.
If the point (xp,yp) lies inside the circumcircle then the
three edges of that triangle are added to the edge buffer
and that triangle is removed.
*/
for(j = 0; j < ntri; j++){
if(complete[j])
continue;
x1 = pxyz[v[j].p1].x;
y1 = pxyz[v[j].p1].y;
x2 = pxyz[v[j].p2].x;
y2 = pxyz[v[j].p2].y;
x3 = pxyz[v[j].p3].x;
y3 = pxyz[v[j].p3].y;
inside = CircumCircle(xp, yp, x1, y1, x2, y2, x3, y3, xc, yc, r);
if (xc + r < xp)
// Suggested
// if (xc + r + EPSILON < xp)
complete[j] = true;
if(inside){
/* Check that we haven't exceeded the edge list size */
if(nedge + 3 >= emax){
emax += 100;
p_EdgeTemp = new IEDGE[emax];
for (int i = 0; i < nedge; i++) { // Fix by John Bowman
p_EdgeTemp[i] = edges[i];
}
delete []edges;
edges = p_EdgeTemp;
}
edges[nedge+0].p1 = v[j].p1;
edges[nedge+0].p2 = v[j].p2;
edges[nedge+1].p1 = v[j].p2;
edges[nedge+1].p2 = v[j].p3;
edges[nedge+2].p1 = v[j].p3;
edges[nedge+2].p2 = v[j].p1;
nedge += 3;
v[j] = v[ntri-1];
complete[j] = complete[ntri-1];
ntri--;
j--;
}
}
/*
Tag multiple edges
Note: if all triangles are specified anticlockwise then all
interior edges are opposite pointing in direction.
*/
for(j = 0; j < nedge - 1; j++){
for(k = j + 1; k < nedge; k++){
if((edges[j].p1 == edges[k].p2) && (edges[j].p2 == edges[k].p1)){
edges[j].p1 = -1;
edges[j].p2 = -1;
edges[k].p1 = -1;
edges[k].p2 = -1;
}
/* Shouldn't need the following, see note above */
if((edges[j].p1 == edges[k].p1) && (edges[j].p2 == edges[k].p2)){
edges[j].p1 = -1;
edges[j].p2 = -1;
edges[k].p1 = -1;
edges[k].p2 = -1;
}
}
}
/*
Form new triangles for the current point
Skipping over any tagged edges.
All edges are arranged in clockwise order.
*/
for(j = 0; j < nedge; j++) {
if(edges[j].p1 < 0 || edges[j].p2 < 0)
continue;
v[ntri].p1 = edges[j].p1;
v[ntri].p2 = edges[j].p2;
v[ntri].p3 = i;
complete[ntri] = false;
ntri++;
}
}
/*
Remove triangles with supertriangle vertices
These are triangles which have a vertex number greater than nv
*/
for(i = 0; i < ntri; i++) {
if(v[i].p1 >= nv || v[i].p2 >= nv || v[i].p3 >= nv) {
v[i] = v[ntri-1];
ntri--;
i--;
}
}
delete[] edges;
delete[] complete;
return 0;
}
int XYZCompare(const void *v1, const void *v2){
XYZ *p1, *p2;
p1 = (XYZ*)v1;
p2 = (XYZ*)v2;
if(p1->x < p2->x)
return(-1);
else if(p1->x > p2->x)
return(1);
else
return(0);
}
I didn't go with a debugger, but from the resulting triangles it seems that this is an accuracy/ambiguity problem.
When you are triangulating a square there are two ways to split it into triangles and both are OK from Delaunay criteria (circumscribed circle center is on border of triangle).
So if you evaluate every triangle independently you may sometimes get even 4 triangles (depending on implementation).
Normally in such cases I recommend to build algorithm as a series of questions which cannot produce contradicting answers. In this case the question is "to which point goes triangle based on edge (1,0)-(1,1)". But often this requires significant changes to the algorithm.
A quick fix usually involves adding some tolerances for comparisons and extra checks (like non-intersecting triangles). But usually it just makes problems rarer.
Most likely you didn't delete all the double edges, especially not the edges from same triangles but with vertices only in another order. The correct function is in the answer from #cMinor.

How to blur SDL_Surface without shaders?

I want to add blur effect to drawing text. I use SDL2 and SDL_TTF.
SDL_Surface has a transparency.
How to do it without shaders?
Below is the algorithm that I use. This is a simple averaging.
Uint32 p;
Uint8 r, g, b, a;
int x, y, px, py;
int blur_sum_factor;
for (y = 0; y < sfc_blur->h; y++)
{
for (x = 0; x < sfc_blur->w; x++)
{
double rd = 0.0, gd = 0.0, bd = 0.0, ad = 0.0;
blur_sum_factor = 0;
for (py = -blur_size; py <= blur_size; py++)
{
for (px = -blur_size; px <= blur_size; px++)
{
int x1 = x + px;
int y1 = y + py;
if (x1 < 0 || x1 >= sfc_blur->w || y1 < 0 || y1 >= sfc_blur->h)
continue;
p = get_pixel32(sfc_blur, x1, y1);
SDL_GetRGBA(p, sfc_blur->format, &r, &g, &b, &a);
rd += r;
gd += g;
bd += b;
blur_sum_factor++;
ad += a;
}
}
rd /= blur_sum_factor;
gd /= blur_sum_factor;
bd /= blur_sum_factor;
ad /= blur_sum_factor;
r = (Uint8)rd;
g = (Uint8)gd;
b = (Uint8)bd;
a = (Uint8)ad;
p = SDL_MapRGBA(sfc_blur_target->format, r, g, b, a);
put_pixel32(sfc_blur_target, x, y, p);
}
}
In result I have a dark area around the text.
(red background for better demonstration - the blur is applied only to text with transparency.)
p.s. I had never used shaders. And in this task I can't use shaders (even if I wanted it).
I solved this problem. I create two SDL_Surface: the first text and the second with the background color as the text. And then I make a blurry only alpha channel:
for (y = 0; y < sfc_blur->h; y++)
{
for (x = 0; x < sfc_blur->w; x++)
{
double rd = 0.0, gd = 0.0, bd = 0.0, ad = 0.0;
blur_sum_factor = 0;
for (py = -blur_size; py <= blur_size; py++)
{
for (px = -blur_size; px <= blur_size; px++)
{
int x1 = x + px;
int y1 = y + py;
if (x1 < 0 || x1 >= sfc_blur->w || y1 < 0 || y1 >= sfc_blur->h)
continue;
p = get_pixel32(sfc_blur, x1, y1);
SDL_GetRGBA(p, sfc_blur->format, &r, &g, &b, &a);
blur_sum_factor++;
ad += a;
}
}
ad /= blur_sum_factor;
p = get_pixel32(sfc_blur_target, x, y);
SDL_GetRGB(p, sfc_blur_target->format, &r, &g, &b);
a = (Uint8)ad;
p = SDL_MapRGBA(sfc_blur_target->format, r, g, b, a);
put_pixel32(sfc_blur_target, x, y, p);
}
}
Next I want to add the Gaussian Blur and parallelize the process.

Calculating fast line end point

What i want is that, I have info of 2 points, the starting x,y and mid point x,y and i need to find end line like until some kind of border, like window
here is what I do:
//function for calculating the end point from one location, to specific end location
//like a bullet moving forward in a line
//x,y start location(mouse), x2,y2(rect point location one of the 4) mid point, qx,qy end point(shadow or triangle draw location)
void screenEnd(int x, int y, int x2, int y2, int*qx,int*qy)
{
x = x2-x;
y = y2-y;
float tx = x2,ty = y2;
float result = atan2((float)y,(float)x) * 180 / PI;
float tempx = cos ( result * PI / 180.0 );
float tempy = sin ( result * PI / 180.0 );
bool check = true;
//this part needs optimization
while(check)
{
if(tx < 0|| ty < 0|| tx > 1280 || ty > 720)
{
check = false;
}
else
{
tx += tempx;
ty += tempy;
}
}
*qx = tx;
*qy = ty;
}
what I do is just increase point until it reaches the end.
Is there any way faster?
A classic window clipping task.
Consider a parametric equation where p is the point (x,y).
p(0) = x, y
p(0.5) = x2, y2
p(1) = x+2*(x2-x), y + 2*(y2-y)
p(t) = p(0) + t*(p(1) - p(0))
clip window = 0,0 to 720, 1280 (suspect you really want 719,1279)
The segment to draw initially ranges from t=0.0 to t=1.0. The segment is tested against each of the 4 sides of the bounding box, potentially reducing the t range. Maybe even eliminating all together.
Follows is some old code, enough to get you going.
#include <math.h>
int cliptest(int dz, int z, double *t0, double *t1) {
if (dz < 0) {
double t = ((double) z) / dz;
if (t > *t1)
return 0;
if (t > *t0)
*t0 = t;
} else if (dz > 0) {
double t = ((double) z) / dz;
if (t < *t0)
return 0;
if (t < *t1)
*t1 = t;
} else {
if (z < 0)
return 0;
}
return 1;
}
int clipper(int *px0, int *py0, int *px1, int *py1, int minx, int miny,
int maxx, int maxy) {
double t0, t1;
int dx, dy;
t0 = 0.0;
t1 = 1.0;
dy = *py1 - *py0;
dx = *px1 - *px0;
if (cliptest(-dx, *px0 - minx, &t0, &t1)
&& cliptest(dx, maxx - *px0, &t0, &t1)
&& cliptest(-dy, *py0 - miny, &t0, &t1)
&& cliptest(dy, maxy - *py0, &t0, &t1)) {
if (t1 < 1.0) {
*px1 = round(*px0 + t1*dx);
*py1 = round(*py0 + t1*dy);
}
if (t0 > 0.0) {
*px0 = round(*px0 + t0*dx);
*py0 = round(*py0 + t0*dy);
}
return 1;
}
return 0;
}
int x0 = x;
int y0 = y;
int x1 = x + 2*(x2-x); // Form end point
int y1 = x + 2*(y2-y);
if (clipper(&x0, &y0, &x1, &y1, 0, 0, 720, 1280))
Draw(x0, y0, x1, y2);
else
Handle_LineTotallyClippedOut();

Roguelike FOV problem

I am working on a college compsci project and I would like some help with a field of view algorithm. I works mostly, but in some situations the algorithm sees through walls and hilights walls the player should not be able to see.
void cMap::los(int x0, int y0, int radius)
{ //Does line of sight from any particular tile
for(int x = 0; x < m_Height; x++) {
for(int y = 0; y < m_Width; y++) {
getTile(x,y)->setVisible(false);
}
}
double xdif = 0;
double ydif = 0;
bool visible = false;
float dist = 0;
for (int x = MAX(x0 - radius,0); x < MIN(x0 + radius, m_Height); x++) { //Loops through x values within view radius
for (int y = MAX(y0 - radius,0); y < MIN(y0 + radius, m_Width); y++) { //Loops through y values within view radius
xdif = pow( (double) x - x0, 2);
ydif = pow( (double) y - y0, 2);
dist = (float) sqrt(xdif + ydif); //Gets the distance between the two points
if (dist <= radius) { //If the tile is within view distance,
visible = line(x0, y0, x, y); //check if it can be seen.
if (visible) { //If it can be seen,
getTile(x,y)->setVisible(true); //Mark that tile as viewable
}
}
}
}
}
bool cMap::line(int x0,int y0,int x1,int y1)
{
bool steep = abs(y1-y0) > abs(x1-x0);
if (steep) {
swap(x0, y0);
swap(x1, y1);
}
if (x0 > x1) {
swap(x0,x1);
swap(y0,y1);
}
int deltax = x1-x0;
int deltay = abs(y1-y0);
int error = deltax/2;
int ystep;
int y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
for (int x = x0; x < x1; x++) {
if ( steep && getTile(y,x)->isBlocked()) {
getTile(y,x)->setVisible(true);
getTile(y,x)->setDiscovered(true);
return false;
} else if (!steep && getTile(x,y)->isBlocked()) {
getTile(x,y)->setVisible(true);
getTile(x,y)->setDiscovered(true);
return false;
}
error -= deltay;
if (error < 0) {
y = y + ystep;
error = error + deltax;
}
}
return true;
}
If anyone could help me make the first blocked tiles visible but stops the rest, I would appreciate it.
thanks,
Manderin87
You seem to be attempting to create a raycasting algorithm. I assume you have knowledge of how Bresenham's lines work, so I'll cut to the chase.
Instead of checking the visibility of each cell in the potential field of view, you only need to launch Bresenham lines from the FOV centre towards each cell at the very perimetre of the potential FOV area (the square you loop through). At each step of the Bresenham line, you check the cell status. The pseudocode for each ray would go like this:
while (current_cell != destination) {
current_cell.visible = true;
if (current_cell.opaque) break;
else current_cell = current_cell.next();
}
Please remember that raycasting produces tons of artifacts and you might also need postprocessing after you have calculated your field of view.
Some useful resources:
ray casting on Roguebasin
ray casting FOV implementation in libtcod (in C, you can dig through the repository for a C++ wrapper to it)
a FOV study