Polygon corners with GL_LINE

I was going to mention in my later response, this person’s answer has worked for me. I’m currently hooking that in, then will get some screenshots up.

Edit: Now that I put this to use, it freezes the screen a bit. I wonder what kind of performance/functional drawbacks that presents? Seems like most games I’ve played don’t do that but you can tell it’s doing something sometimes. Perhaps this should go on another thread?

Hopefully this album will cover it. Not sure if it would be preferred to have set this up here. Can do tho if so. But yea, the comments on those images matter. Let me know if you need any other info. Thanks!

Assuming you’re using JOML, your vector math code is completely broken. add(), scale(), normalize(), subtract(), etc all modify the current object; they don’t return a new object.

Here are a few of the problems your code has:

  • On line 10, you take V1, subtract V2 from it, then normalize it. In other words, L1 and V1 are the same objects, and you’ve permanently modified V1 so that the computation on line 8 will be wrong.
    - On line 15, G1 is ALSO the same object as V1. rotate90Degrees() actually does return a new vector, but L1 still gets L2 added to it and is normalized permanently.
  • On line 40, you’re again modifying V1 like crazy.

Honestly, this kind of math is so simple that it doesn’t really warrant using vector classes to accomplish it. I’d recommend you start with something simpler: A function for drawing a single line given four points (V1 to V4). It should only draw a single line between the V2 and V3, but needs V1 and V4 to get the ends of the line right. Using such a function, you can easily draw a box by just calling it 4 times for each side.

It’s a different Vector2f class. Not JOML. It does the things you’d think it should do. Line 10 subtracts V1 from V2 and doesn’t modify V1 for instance.

Yea, scaled back version is probably the way to go. At least for proof of concept.

Got it working. The Vector2f class I used has its documentation backwards. I specifically looked which way subtract is when I first tried to do this. It is opposite how they say it. Adjusting accordingly fixed it. Do most people just use JOML? I got this class while I was learning. It’s from MIT.

I backed up and was going to implement a version that just took 4 coordinates and made 4 new coordinates that were 45degrees inward. This is where I found that the subtract is backwards how they say.

I’m going to include my code and some screenshots in case they can help anyone else. Thanks for the thorough help! ;D

My parentheses went ham as I was trying to debug. CBA to delete the superfluous ones now.

	//take in mouse coordinates @click and present and make a box
	public void drawDragBox3(double mX, double mY, double mX2, double mY2)
	{
    	float lineWidth = 50f;
    	
    	Vector2f V1 = new Vector2f((float)mX, (float)mY);
    	Vector2f V2 = new Vector2f((float)mX, (float)mY2);
    	Vector2f V3 = new Vector2f((float)mX2, (float)mY2);
    	Vector2f V4 = new Vector2f((float)mX2, (float)mY);        	

    	Vector2f L1 = (V2.subtract(V1)).normalize(); //subtract V1 [b]FROM[/b] V2 and then normalize
    	Vector2f L2 = (V3.subtract(V2)).normalize(); 
    	Vector2f L3 = (V4.subtract(V3)).normalize();
    	Vector2f L4 = (V1.subtract(V4)).normalize();
    	
    	Vector2f G1 = rotate90Degrees((L1.add(L2)).normalize());
    	Vector2f G2 = rotate90Degrees((L2.add(L3)).normalize());
    	Vector2f G3 = rotate90Degrees((L3.add(L4)).normalize());
    	Vector2f G4 = rotate90Degrees((L4.add(L1)).normalize());
    	
    	double x1 = 1 / Math.sqrt(((L4.dot(L1))*0.5)+0.5);
    	double y1 = 1 / Math.sqrt(((L1.dot(L2))*0.5)+0.5);
    	
    	double x2 = 1 / Math.sqrt(((L1.dot(L2))*0.5)+0.5); //the line theagentd's example was built for
    	double y2 = 1 / Math.sqrt(((L2.dot(L3))*0.5)+0.5);
    	
    	double x3 = 1 / Math.sqrt(((L2.dot(L3))*0.5)+0.5);
    	double y3 = 1 / Math.sqrt(((L3.dot(L4))*0.5)+0.5);
    	
    	double x4 = 1 / Math.sqrt(((L3.dot(L4))*0.5)+0.5);
    	double y4 = 1 / Math.sqrt(((L4.dot(L1))*0.5)+0.5);    	

    	Vector2f A1 = V1.add(G4.scale((float)(lineWidth/2 * x1)));
    	Vector2f A2 = V1.subtract((G4.scale((float)(lineWidth/2 * x1)))); //subtract FROM V1
    	
    	Vector2f A3 = V2.add(G1.scale((float)(lineWidth/2 * y1)));
    	Vector2f A4 = V2.subtract((G1.scale((float)(lineWidth/2 * y1))));
    	
    	Vector2f B1 = V2.add(G1.scale((float)(lineWidth/2 * x2)));
    	Vector2f B2 = V2.subtract((G1.scale((float)(lineWidth/2 * x2))));
    	
    	Vector2f B3 = V3.add(G2.scale((float)(lineWidth/2 * y2)));
    	Vector2f B4 = V3.subtract((G2.scale((float)(lineWidth/2 * y2))));
    	
    	Vector2f C1 = V3.add(G2.scale((float)(lineWidth/2 * x3)));
    	Vector2f C2 = V3.subtract((G2.scale((float)(lineWidth/2 * x3))));
    	
    	Vector2f C3 = V4.add(G3.scale((float)(lineWidth/2 * y3)));
    	Vector2f C4 = V4.subtract((G3.scale((float)(lineWidth/2 * y3))));
    	
    	Vector2f D1 = V4.add(G3.scale((float)(lineWidth/2 * x4)));
    	Vector2f D2 = V4.subtract((G3.scale((float)(lineWidth/2 * x4))));
    	
    	Vector2f D3 = V1.add(G4.scale((float)(lineWidth/2 * y4)));
    	Vector2f D4 = V1.subtract((G4.scale((float)(lineWidth/2 * y4))));
		
    	glDisable(GL_BLEND);
    	glColor3f(1, 0, 0);
        GL11.glLineWidth(lineWidth);
        //glEnable(GL_LINE_SMOOTH);
        glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
        GL11.glBegin(GL_TRIANGLE_STRIP); 
        
        glVertex2f(A1.x, A1.y);        
        glVertex2f(A4.x, A4.y);
        glVertex2f(A3.x, A3.y);
        
        glVertex2f(B4.x, B4.y);
        glVertex2f(B3.x, B3.y);
        
        glVertex2f(C4.x, C4.y);
        glVertex2f(C3.x, C3.y);
        
        glVertex2f(D4.x, D4.y);
        glVertex2f(D3.x, D3.y);
        glVertex2f(A4.x, A4.y);

        glEnd();
        
         glColor3f(1, 1, 1);
	}

Working demo:

Running with glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);

An image I made to help me sort this out:

That looks 100% correct! Good job! I’m glad you got it working.

Note that there are a couple of special cases you should be aware of.

  • As the angle between L1 and L2 gets smaller, x tends to infinity. This makes sense if you want a pointy end to the line (as is the case for your box rendering), but it may not always give the best result. In essence, it can cause the line to be drawn as much longer than it really is, which could be problematic.
  • Since you need four points in total draw a single line between the middle two points, it can become difficult to draw line strips where the first and last lines are missing one neighbor. In this case, you can either introduce a special case or generate the missing points from the ones you have.

Here is some more information:

  • Since you have 100% control of the vertices, it actually becomes possible to pick a line width per vertex. This allows you to draw continuous lines with varying thickness, which can look really nice.
  • Again, since you’re emulating lines with triangles, there are no limit to the line width. Usually it’s limited to between 1 and 16 or something like that.
  • This system does not work with line smoothing.
  • You can however use both MSAA and shader-based anti-aliasing to achieve extremely high-quality anti-aliasing.
  • Although the line width can be under 1 pixel, doing so will cause bad aliasing. It’s a good idea to clamp the line width to 1 pixel and instead reduce the alpha of thin lines. Example: line width is 0.5 —> make line width 1.0 and multiply alpha by 0.5.

I know just what you are talking about with the edges going off crazy at sharp angles. I see it a lot in Adobe Illustrator. It looked to me like your example takes this into account? I wasn’t sure if you were making small lines there yourself or if it was the answer for that angle problem.

[quote]or generate the missing points from the.
[/quote]
From the what? I reckon the vertex it is equal to.

Argh, I suck at this typing thing. xD

If you’re missing V1, you can just set L1 to L2 for example.

EDIT: Also, I strongly STRONGLY recommend JOML. JOML is the best thing that has happened to Java game development in a decent time. It’s fast, KaiHH that develops it is super responsive and helpful if you’re missing some feature, it generates zero garbage when used correctly and has pretty much anything that you could ever ask for. However, in this case you’re probably better off just using raw floats as the vectors are kinda unnecessary in this case.