代码
#include <GLFW/glfw3.h>
#include <iostream>
#include <vector>
#define POS_P 0.5f
#define POS_N -0.5f
#define WIDTH 960.f
#define HEIGHT 600.f
using namespace std;
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
struct Color {
double r, g, b;
Color ( ) { }
Color ( double x, double y, double z)
: r ( x) , g ( y) , b ( z) { }
} YELLOW ( 1 , 1 , 0 ) , RED ( 1 , 0 , 0 ) , BLACK ( 0.2 , 0.2 , 0.2 ) ;
struct Point {
double x, y;
Point ( ) { }
Point ( double a, double b)
: x ( a) , y ( b) { }
} ;
vector< Point> points;
void drawPolygon ( Color C) {
glBegin ( GL_LINE_LOOP) ;
glColor3f ( C. r, C. g, C. b) ;
for ( auto p : points) {
glVertex2f ( p. x, p. y) ;
}
glEnd ( ) ;
}
bool Inside ( Point p, int boundary) {
switch ( boundary) {
case 0 :
if ( p. x >= POS_N) return true ;
break ;
case 1 :
if ( p. y <= POS_P) return true ;
break ;
case 2 :
if ( p. x <= POS_P) return true ;
break ;
case 3 :
if ( p. y >= POS_N) return true ;
break ;
default :
return false ;
}
return false ;
}
Point intersect ( Point & S, Point & P, int boundary) {
Point tmp;
double dy = P. y - S. y, dx = P. x - S. x;
if ( boundary == 0 ) {
tmp. x = POS_N;
tmp. y = S. y + ( POS_N - S. x) * ( dy / dx) ;
}
else if ( boundary == 1 ) {
tmp. y = POS_P;
tmp. x = S. x + ( POS_P - S. y) * ( dx / dy) ;
}
else if ( boundary == 2 ) {
tmp. x = POS_P;
tmp. y = S. y + ( POS_P - S. x) * ( dy / dx) ;
}
else {
tmp. y = POS_N;
tmp. x = S. x + ( POS_N - S. y) * ( dx / dy) ;
}
return tmp;
}
void sutherland_hodgman ( ) {
vector< Point> clipPoints = points;
for ( int boundary = 0 ; boundary < 4 ; boundary++ ) {
vector< Point> remainPoints;
for ( int i = 0 ; i < clipPoints. size ( ) ; i++ ) {
Point S, P;
S = clipPoints[ i] ;
if ( i == clipPoints. size ( ) - 1 ) P = clipPoints[ 0 ] ;
else P = clipPoints[ i + 1 ] ;
if ( Inside ( S, boundary) ) {
if ( Inside ( P, boundary) ) {
remainPoints. push_back ( P) ;
}
else {
Point tmp = intersect ( S, P, boundary) ;
remainPoints. push_back ( tmp) ;
}
}
else {
if ( Inside ( P, boundary) ) {
Point tmp = intersect ( S, P, boundary) ;
remainPoints. push_back ( tmp) ;
remainPoints. push_back ( P) ;
}
}
}
clipPoints = remainPoints;
}
points = clipPoints;
}
void mouseButtonCallback ( GLFWwindow * window, int button, int action, int mods) {
if ( button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
double xpos, ypos;
glfwGetCursorPos ( window, & xpos, & ypos) ;
xpos = ( xpos - WIDTH / 2 ) / WIDTH * 2 ;
ypos = ( HEIGHT / 2 - ypos) / HEIGHT * 2 ;
points. emplace_back ( xpos, ypos) ;
}
else if ( button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
sutherland_hodgman ( ) ;
}
}
void keyCallback ( GLFWwindow * window, int key, int scancode, int action, int mods) {
if ( key == GLFW_KEY_SPACE && action == GLFW_PRESS) {
points. clear ( ) ;
}
}
int main ( void )
{
GLFWwindow* window;
if ( ! glfwInit ( ) )
return - 1 ;
window = glfwCreateWindow ( WIDTH, HEIGHT, "PolygonClip" , NULL , NULL ) ;
glfwSetWindowPos ( window, 600 , 200 ) ;
if ( ! window)
{
glfwTerminate ( ) ;
return - 1 ;
}
glfwMakeContextCurrent ( window) ;
while ( ! glfwWindowShouldClose ( window) )
{
glClearColor ( 0.2f , 0.3f , 0.3f , 1.0f ) ;
glClear ( GL_COLOR_BUFFER_BIT) ;
glLineWidth ( 3 ) ;
glColor3f ( 0.95f , 0.95f , 0.95f ) ;
glRectf ( POS_N, POS_N, POS_P, POS_P) ;
glfwSetMouseButtonCallback ( window, mouseButtonCallback) ;
glfwSetKeyCallback ( window, keyCallback) ;
drawPolygon ( RED) ;
glfwSwapBuffers ( window) ;
glfwPollEvents ( ) ;
}
glfwTerminate ( ) ;
return 0 ;
}