Browse Source

Replace line drawing via GL_LINE with custom line drawing (issue #153)

Allows for correctly scaleable lines, (very) big line widths. Corners in
rectangles/triangles/... join up nicely (issue #197).

--HG--
branch : minor
vrld 14 years ago
parent
commit
2a42c64a35

+ 133 - 302
src/modules/graphics/opengl/Graphics.cpp

@@ -20,6 +20,7 @@
 
 #include <common/config.h>
 #include <common/math.h>
+#include <common/Vector.h>
 
 #include "Graphics.h"
 
@@ -36,7 +37,7 @@ namespace opengl
 {
 
 	Graphics::Graphics()
-		: currentFont(0)
+		: currentFont(0), lineWidth(1)
 	{
 		// Indicates that there is no screen
 		// created yet.
@@ -100,19 +101,8 @@ namespace opengl
 		//get color mode
 		glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &mode);
 		s.colorMode = (mode == GL_MODULATE) ? Graphics::COLOR_MODULATE : Graphics::COLOR_REPLACE;
-		//get the line width (directly to corresponding variable)
-		glGetFloatv(GL_LINE_WIDTH, &s.lineWidth);
 		//get line style
-		s.lineStyle = (glIsEnabled(GL_LINE_SMOOTH) == GL_TRUE) ? Graphics::LINE_SMOOTH : Graphics::LINE_ROUGH;
-		//get line stipple
-		s.stipple = (glIsEnabled(GL_LINE_STIPPLE) == GL_TRUE);
-		if (s.stipple)
-		{
-			//get the stipple repeat
-			glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &s.stippleRepeat);
-			//get the stipple pattern
-			glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &s.stipplePattern);
-		}
+		s.lineStyle = (glIsEnabled(GL_POLYGON_SMOOTH) == GL_TRUE) ? Graphics::LINE_SMOOTH : Graphics::LINE_ROUGH;
 		//get the point size
 		glGetFloatv(GL_POINT_SIZE, &s.pointSize);
 		//get point style
@@ -136,11 +126,7 @@ namespace opengl
 		setBackgroundColor(s.backgroundColor);
 		setBlendMode(s.blendMode);
 		setColorMode(s.colorMode);
-		setLine(s.lineWidth, s.lineStyle);
-		if (s.stipple)
-			setLineStipple(s.stipplePattern, s.stippleRepeat);
-		else
-			setLineStipple();
+		setLine(lineWidth, s.lineStyle);
 		setPoint(s.pointSize, s.pointStyle);
 		if (s.scissor)
 			setScissor(s.scissorBox[0], s.scissorBox[1], s.scissorBox[2], s.scissorBox[3]);
@@ -260,8 +246,7 @@ namespace opengl
 		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 		// Enable line/point smoothing.
-		glEnable(GL_LINE_SMOOTH);
-		glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
+		setLineStyle(LINE_SMOOTH);
 		glEnable(GL_POINT_SMOOTH);
 		glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
 
@@ -608,45 +593,30 @@ namespace opengl
 
 	void Graphics::setLineWidth( float width )
 	{
-		glLineWidth(width);
+		lineWidth = width;
 	}
 
 	void Graphics::setLineStyle(Graphics::LineStyle style )
 	{
+		// XXX: actually enables antialiasing for _all_ polygons.
+		// may need investigation if wanted or not
+		// maybe rename to something else?
 		if(style == LINE_ROUGH)
-			glDisable (GL_LINE_SMOOTH);
+			glDisable (GL_POLYGON_SMOOTH);
 		else // type == LINE_SMOOTH
 		{
-			glEnable (GL_LINE_SMOOTH);
-			glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+			glEnable (GL_POLYGON_SMOOTH);
+			glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST);
 		}
 	}
 
 	void Graphics::setLine( float width, Graphics::LineStyle style )
 	{
-		glLineWidth(width);
+		setLineWidth(width);
 
 		if(style == 0)
 			return;
-
-		if(style == LINE_ROUGH)
-			glDisable (GL_LINE_SMOOTH);
-		else // type == LINE_SMOOTH
-		{
-			glEnable (GL_LINE_SMOOTH);
-			glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
-		}
-	}
-
-	void Graphics::setLineStipple()
-	{
-		glDisable(GL_LINE_STIPPLE);
-	}
-
-	void Graphics::setLineStipple(unsigned short pattern, int repeat)
-	{
-		glEnable(GL_LINE_STIPPLE);
-		glLineStipple((GLint)repeat, (GLshort)pattern);
+		setLineStyle(style);
 	}
 
 	float Graphics::getLineWidth()
@@ -658,25 +628,12 @@ namespace opengl
 
 	Graphics::LineStyle Graphics::getLineStyle()
 	{
-		if(glIsEnabled(GL_LINE_SMOOTH) == GL_TRUE)
+		if(glIsEnabled(GL_POLYGON_SMOOTH) == GL_TRUE)
 			return LINE_SMOOTH;
 		else
 			return LINE_ROUGH;
 	}
 
-	int Graphics::getLineStipple(lua_State * L)
-	{
-		if(glIsEnabled(GL_LINE_STIPPLE) == GL_FALSE)
-			return 0;
-
-		GLint factor, pattern;
-		glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &pattern);
-		glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &factor);
-		lua_pushinteger(L, pattern);
-		lua_pushinteger(L, factor);
-		return 2;
-	}
-
 	void Graphics::setPointSize( float size )
 	{
 		glPointSize((GLfloat)size);
@@ -805,149 +762,90 @@ namespace opengl
 		glEnable(GL_TEXTURE_2D);
 	}
 
-	void Graphics::line( float x1, float y1, float x2, float y2 )
+	// calculate line boundary intersection vertices for current line
+	// dependent on the current *and next* line segment
+	static void pushIntersectionPoints(Vector *vertices, int pos, float halfwidth, const Vector& p, const Vector& q, const Vector& r)
 	{
-		glDisable(GL_TEXTURE_2D);
-		glPushMatrix();
-			glBegin(GL_LINES);
-				glVertex2f(x1, y1);
-				glVertex2f(x2, y2);
-			glEnd();
-		glPopMatrix();
-		glEnable(GL_TEXTURE_2D);
+		// calculate line directions
+		Vector s = (q - p);
+		Vector t = (r - q);
+
+		// calculate vertex displacement vectors
+		Vector d1 = s.getNormal();
+		Vector d2 = t.getNormal();
+		d1.normalize();
+		d2.normalize();
+		float det_norm = d1 ^ d2;
+		d1 *= halfwidth;
+		d2 *= halfwidth;
+
+		// lines parallel -> assume intersection at displacement points
+		if (fabs(det_norm) <= .03) {
+			vertices[pos]     = q - d2;
+			vertices[pos + 1] = q + d2;
+			return;
+		}
+
+		// real intersection -> calculate boundary intersection points
+		float det = s ^ t;
+		Vector d = d1 - d2;
+		Vector b = s - d; // s = q - p
+		Vector c = s + d;
+		float lambda = (b ^ t) / det;
+		float mu     = (c ^ t) / det;
+
+		// ordering for GL_TRIANGLE_STRIP
+		vertices[pos]   = p - d1 + s * mu;
+		vertices[pos+1] = p + d1 + s * lambda;
 	}
 
-	int Graphics::polyline( lua_State * L)
+	void Graphics::polyline(const float* coords, size_t count, bool looping)
 	{
-		// Get number of params.
-		int args = lua_gettop(L);
-		bool table = false;
+		Vector *vertices = new Vector[count]; // two vertices for every line end-point
+		Vector p,q,r;
+
+		r = Vector(coords[0], coords[1]);
+		if (looping) q = Vector(coords[count-4], coords[count-3]);
+		else         q = r * 2 - Vector(coords[2], coords[3]);
 
-		if (args == 1) { // we've got a table, hopefully
-			int type = lua_type(L, 1);
-			if (type != LUA_TTABLE)
-				return luaL_error(L, "Function requires a table or series of numbers");
-			table = true;
-			args = lua_objlen(L, 1);
+		for (size_t i = 0; i+3 < count; i += 2) {
+			p = q;
+			q = r;
+			r = Vector(coords[i+2], coords[i+3]);
+			pushIntersectionPoints(vertices, i, lineWidth/2, p,q,r);
 		}
 
-		if (args % 2) // an odd number of arguments, no good for a polyline
-			return luaL_error(L, "Number of vertices must be a multiple of two");
-		else if (args < 4)
-			return luaL_error(L, "Need at least two vertices to draw a line");
+		p = q;
+		q = r;
+		if (looping) r = Vector(coords[2], coords[3]);
+		else         r += (q-p);
+		pushIntersectionPoints(vertices, count-2, lineWidth/2, p,q,r);
 
-		// right, let's draw this polyline, then
 		glDisable(GL_TEXTURE_2D);
-		glBegin(GL_LINE_STRIP);
-		if (table) {
-			for (int i = 1; i < args; i += 2) {
-				lua_pushnumber(L, i);   // x coordinate
-				lua_rawget(L, 1);
-				lua_pushnumber(L, i+1); // y coordinate
-				lua_rawget(L, 1);
-				glVertex2f((GLfloat)lua_tonumber(L, -2), (GLfloat)lua_tonumber(L, -1));
-				lua_pop(L, 2);
-			}
-		} else {
-			for (int i = 1; i < args; i+=2) {
-				glVertex2f((GLfloat)lua_tonumber(L, i), (GLfloat)lua_tonumber(L, i+1));
-			}
-		}
-		glEnd();
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glVertexPointer(2, GL_FLOAT, 0, (const GLvoid*)vertices);
+		glDrawArrays(GL_TRIANGLE_STRIP, 0, count);
+		glDisableClientState(GL_VERTEX_ARRAY);
 		glEnable(GL_TEXTURE_2D);
-		return 0;
+
+		delete[] vertices;
 	}
 
 	void Graphics::triangle(DrawMode mode, float x1, float y1, float x2, float y2, float x3, float y3 )
 	{
-		glDisable(GL_TEXTURE_2D);
-		glPushMatrix();
-
-		switch(mode)
-		{
-		case DRAW_LINE:
-			glBegin(GL_LINE_LOOP);
-				glVertex2f(x1, y1);
-				glVertex2f(x2, y2);
-				glVertex2f(x3, y3);
-			glEnd();
-			break;
-
-		default:
-		case DRAW_FILL:
-			glBegin(GL_TRIANGLES);
-				glVertex2f(x1, y1);
-				glVertex2f(x2, y2);
-				glVertex2f(x3, y3);
-			glEnd();
-			break;
-		}
-
-		glPopMatrix();
-		glEnable(GL_TEXTURE_2D);
+		float coords[] = { x1,y1, x2,y2, x3,y3, x1,y1 };
+		polygon(mode, coords, 4 * 2);
 	}
 
 	void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h)
 	{
-		glDisable(GL_TEXTURE_2D);
-		glPushMatrix();
-
-		switch(mode)
-		{
-		case DRAW_LINE:
-			// offsets here because OpenGL is being a bitch about line drawings
-			glBegin(GL_LINE_LOOP);
-				glVertex2f(x, y);
-				glVertex2f(x, y+h-1);
-				glVertex2f(x+w-1, y+h-1);
-				glVertex2f(x+w-1, y);
-			glEnd();
-			break;
-
-		default:
-		case DRAW_FILL:
-			glBegin(GL_QUADS);
-				glVertex2f(x, y);
-				glVertex2f(x, y+h);
-				glVertex2f(x+w, y+h);
-				glVertex2f(x+w, y);
-			glEnd();
-			break;
-		}
-
-		glPopMatrix();
-		glEnable(GL_TEXTURE_2D);
+		quad(mode, x,y, x,y+h, x+w,y+h, x+w,y);
 	}
 
 	void Graphics::quad(DrawMode mode, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4 )
 	{
-		glDisable(GL_TEXTURE_2D);
-		glPushMatrix();
-
-		switch(mode)
-		{
-		case DRAW_LINE:
-			glBegin(GL_LINE_LOOP);
-				glVertex2f(x1, y1);
-				glVertex2f(x2, y2);
-				glVertex2f(x3, y3);
-				glVertex2f(x4, y4);
-			glEnd();
-			break;
-
-		default:
-		case DRAW_FILL:
-			glBegin(GL_QUADS);
-				glVertex2f(x1, y1);
-				glVertex2f(x2, y2);
-				glVertex2f(x3, y3);
-				glVertex2f(x4, y4);
-			glEnd();
-			break;
-		}
-
-		glPopMatrix();
-		glEnable(GL_TEXTURE_2D);
+		float coords[] = { x1,y1, x2,y2, x3,y3, x4,y4, x1,y1 };
+		polygon(mode, coords, 5 * 2);
 	}
 
 	void Graphics::circle(DrawMode mode, float x, float y, float radius, int points)
@@ -955,144 +853,77 @@ namespace opengl
 		float two_pi = static_cast<float>(LOVE_M_PI * 2);
 		if(points <= 0) points = 1;
 		float angle_shift = (two_pi / points);
+		float phi = .0f;
 
-		glDisable(GL_TEXTURE_2D);
-		glPushMatrix();
-
-		glTranslatef(x, y, 0.0f);
-
-		switch(mode)
-		{
-		case DRAW_LINE:
-			glBegin(GL_LINE_LOOP);
-
-			for(float i = 0; i < two_pi; i+= angle_shift)
-				glVertex2f(radius * sin(i),radius * cos(i));
-
-			glEnd();
-			break;
-
-		default:
-		case DRAW_FILL:
-			glBegin(GL_TRIANGLE_FAN);
+		float *coords = new float[2 * (points + 1)];
+		for (int i = 0; i < points; ++i, phi += angle_shift) {
+			coords[2*i]   = x + radius * cos(phi);
+			coords[2*i+1] = y + radius * sin(phi);
+		}
 
-			for(float i = 0; i < two_pi; i+= angle_shift)
-				glVertex2f(radius * sin(i),radius * cos(i));
+		coords[2*points]   = coords[0];
+		coords[2*points+1] = coords[1];
 
-			glEnd();
-			break;
-		}
+		polygon(mode, coords, (points + 1) * 2);
 
-		glPopMatrix();
-		glEnable(GL_TEXTURE_2D);
+		delete[] coords;
 	}
 	
 	void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1, float angle2, int points)
 	{
-		float angle = angle2 - angle1;
-		if (angle == 0) return;
-		while (angle < 0) angle += LOVE_M_PI * 2;
-		if(points <= 0) points = 1;
-		float angle_shift = (angle / points);
-		
-		glDisable(GL_TEXTURE_2D);
-		glPushMatrix();
-		
-		glTranslatef(x, y, 0.0f);
-		
-		switch(mode)
-		{
-			case DRAW_LINE:
-				glBegin(GL_LINE_LOOP);
-				
-				glVertex2f(0, 0);
-				
-				for(float i = 0; i <= angle+angle_shift/2; i+= angle_shift)
-					glVertex2f(radius * cos(i+angle1),radius * sin(i+angle1));
-				
-				glEnd();
-				break;
-				
-			default:
-			case DRAW_FILL:
-				glBegin(GL_TRIANGLE_FAN);
-				
-				glVertex2f(0, 0);
-				
-				for(float i = 0; i <= angle+angle_shift/2; i+= angle_shift)
-					glVertex2f(radius * cos(i+angle1),radius * sin(i+angle1));
-				
-				glEnd();
-				break;
-		}
-		
-		glPopMatrix();
-		glEnable(GL_TEXTURE_2D);
-	}
-
-	int Graphics::polygon( lua_State * L )
-	{
-		// Get number of params.
-		int n = lua_gettop(L);
-
-		// Need at least two params.
-		if( n < 2 )
-			return luaL_error(L, "Error: function needs at least two parameters.");
-
-		DrawMode mode;
+		angle1 = fmod(angle1, 2 * LOVE_M_PI);
+		angle2 = fmod(angle2, 2 * LOVE_M_PI);
+		if (angle1 == angle2)
+			return;
+		else if (angle1 > angle2)
+			angle2 += LOVE_M_PI * 2;
 
-		const char * str = luaL_checkstring(L, 1);
-		if(!getConstant(str, mode))
-			return luaL_error(L, "Invalid draw mode: %s", str);
 
-		// Get the type of the second argument.
-		int luatype = lua_type(L, 2);
+		if(points <= 0) points = 1;
+		float angle_shift = ((angle2 - angle1) / points);
+		float phi = angle1;
+
+		// GL_POLYGON can only fill-draw convex polygons, so we need to do stuff manually here
+		if (mode == DRAW_LINE) {
+			float *coords = new float[(points + 3) * 2];
+			coords[0] = coords[2 * points + 4] = x;
+			coords[1] = coords[2 * points + 5] = y;
+			for (int i = 0; i <= points; ++i, phi += angle_shift) {
+				coords[2 * (i+1)]     = x + radius * cos(phi);
+				coords[2 * (i+1) + 1] = y - radius * sin(phi);
+			}
+			polyline(coords, (points + 3) * 2); // artifacts at sharp angles if set to looping
 
-		// Perform additional type checking.
-		switch(luatype)
-		{
-		case LUA_TNUMBER:
-			if( n-1 < 6 ) return luaL_error(L, "Error: function requires at least 3 vertices.");
-			if( ((n-1)%2) != 0 ) return luaL_error(L, "Error: number of vertices must be a multiple of two.");
-			break;
-		case LUA_TTABLE:
-			if( (lua_objlen(L, 2)%2) != 0 ) return luaL_error(L, "Error: number of vertices must be a multiple of two.");
-			break;
-		default:
-			return luaL_error(L, "Error: number type or table expected.");
+			delete[] coords;
+		} else {
+			glDisable(GL_TEXTURE_2D);
+			glBegin(GL_TRIANGLE_FAN);
+			glVertex2f(x, y);
+			for (int i = 0; i <= points; ++i, phi += angle_shift)
+				glVertex2f(x + radius * cos(phi), y - radius * sin(phi));
+			glEnd();
+			glEnable(GL_TEXTURE_2D);
 		}
 
+	}
 
-		glDisable(GL_TEXTURE_2D);
-
-		glBegin((mode==DRAW_LINE) ? GL_LINE_LOOP : GL_POLYGON);
-
-		switch(luatype)
-		{
-		case LUA_TNUMBER:
-			for(int i = 2; i<n; i+=2)
-				glVertex2f((GLfloat)lua_tonumber(L, i), (GLfloat)lua_tonumber(L, i+1));
-			break;
-		case LUA_TTABLE:
-			lua_pushnil(L);
-			while (true)
-			{
-				if(lua_next(L, 2) == 0) break;
-				GLfloat x = (GLfloat)lua_tonumber(L, -1);
-				lua_pop(L, 1); // pop value
-				if(lua_next(L, 2) == 0) break;
-				GLfloat y = (GLfloat)lua_tonumber(L, -1);
-				lua_pop(L, 1); // pop value
-				glVertex2f(x, y);
-			}
-			break;
+	/// @param mode    the draw mode
+	/// @param coords  the coordinate array
+	/// @param count   the number of coordinates/size of the array
+	void Graphics::polygon(DrawMode mode, const float* coords, size_t count)
+	{
+		// coords is an array of a closed loop of vertices, i.e.
+		// coords[count-2] = coords[0], coords[count-1] = coords[1]
+		if (mode == DRAW_LINE) {
+			polyline(coords, count, true);
+		} else {
+			glDisable(GL_TEXTURE_2D);
+			glEnableClientState(GL_VERTEX_ARRAY);
+			glVertexPointer(2, GL_FLOAT, 0, (const GLvoid*)coords);
+			glDrawArrays(GL_POLYGON, 0, count / 2); // opengl will close the polygon for us
+			glDisableClientState(GL_VERTEX_ARRAY);
+			glEnable(GL_TEXTURE_2D);
 		}
-
-		glEnd();
-
-		glEnable(GL_TEXTURE_2D);
-
-		return 0;
 	}
 
 	love::image::ImageData * Graphics::newScreenshot(love::image::Image * image)

+ 9 - 36
src/modules/graphics/opengl/Graphics.h

@@ -76,11 +76,7 @@ namespace opengl
 		Graphics::ColorMode colorMode;
 
 		// Line.
-		float lineWidth;
 		Graphics::LineStyle lineStyle;
-		bool stipple;
-		GLint stippleRepeat;
-		GLint stipplePattern;
 
 		// Point.
 		float pointSize;
@@ -107,9 +103,7 @@ namespace opengl
 			backgroundColor.a = 255;
 			blendMode = Graphics::BLEND_ALPHA;
 			colorMode = Graphics::COLOR_MODULATE;
-			lineWidth = 1.0f;
 			lineStyle = Graphics::LINE_SMOOTH;
-			stipple = false;
 			pointSize = 1.0f;
 			pointStyle = Graphics::POINT_SMOOTH;
 			scissor = false;
@@ -126,6 +120,8 @@ namespace opengl
 		Font * currentFont;
 		DisplayMode currentMode;
 
+		float lineWidth;
+
 	public:
 
 		Graphics();
@@ -335,16 +331,6 @@ namespace opengl
 		**/
 		void setLine(float width, LineStyle style);
 
-		/**
-		* Disables line stippling.
-		**/
-		void setLineStipple();
-
-		/**
-		* Sets a line stipple pattern.
-		**/
-		void setLineStipple(unsigned short pattern, int repeat = 1);
-
 		/**
 		* Gets the line width.
 		**/
@@ -355,13 +341,6 @@ namespace opengl
 		**/
 		LineStyle getLineStyle();
 
-		/**
-		* Gets the line stipple pattern and repeat factor.
-		* @return pattern The stipplie bit-pattern.
-		* @return repeat The reapeat factor.
-		**/
-		int getLineStipple(lua_State * L);
-
 		/**
 		* Sets the size of points.
 		**/
@@ -423,20 +402,13 @@ namespace opengl
 		**/
 		void point(float x, float y);
 
-		/**
-		* Draws a line from (x1,y1) to (x2,y2).
-		* @param x1 First x-coordinate.
-		* @param y1 First y-coordinate.
-		* @param x2 Second x-coordinate.
-		* @param y2 Second y-coordinate.
-		**/
-		void line(float x1, float y1, float x2, float y2);
-
 		/**
 		* Draws a series of lines connecting the given vertices.
-		* @param ... Vertex components (x1, y1, x2, y2, etc.)
+		* @param coords Vertex components (x1, y1, x2, y2, etc.)
+		* @param count Coord array size
+		* @param looping Wether the line is joining itself
 		**/
-		int polyline(lua_State * L);
+		void polyline(const float* coords, size_t count, bool looping = false);
 
 		/**
 		* Draws a triangle using the three coordinates passed.
@@ -488,9 +460,10 @@ namespace opengl
 		/**
 		* Draws a polygon with an arbitrary number of vertices.
 		* @param type The type of drawing (line/filled).
-		* @param ... Vertex components (x1, y1, x2, y2, etc).
+		* @param coords Vertex components (x1, y1, x2, y2, etc.)
+		* @param count Coord array size
 		**/
-		int polygon(lua_State * L);
+		void polygon(DrawMode mode, const float* coords, size_t count);
 
 		/**
 		* Creates a screenshot of the view and saves it to the default folder.

+ 64 - 29
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -556,20 +556,6 @@ namespace opengl
 		return 0;
 	}
 
-	int w_setLineStipple(lua_State * L)
-	{
-		if(lua_gettop(L) == 0)
-		{
-			instance->setLineStipple();
-			return 0;
-		}
-
-		unsigned short pattern = (unsigned short)luaL_checkint(L, 1);
-		int repeat = luaL_optint(L, 2, 1);
-		instance->setLineStipple(pattern, repeat);
-		return 0;
-	}
-
 	int w_getLineWidth(lua_State * L)
 	{
 		lua_pushnumber(L, instance->getLineWidth());
@@ -585,11 +571,6 @@ namespace opengl
 		return 1;
 	}
 
-	int w_getLineStipple(lua_State * L)
-	{
-		return instance->getLineStipple(L);
-	}
-
 	int w_setPointSize(lua_State * L)
 	{
 		float size = (float)luaL_checknumber(L, 1);
@@ -776,15 +757,32 @@ namespace opengl
 	int w_line(lua_State * L)
 	{
 		int args = lua_gettop(L);
-		if( args == 1 || args > 4) {
-			instance->polyline(L);
+		bool is_table = false;
+		if (args == 1 && lua_istable(L, 1)) {
+			args = lua_objlen(L, 1);
+			is_table = true;
+		}
+		if (args % 2 != 0)
+			return luaL_error(L, "Number of vertices must be a multiple of two");
+		else if (args < 4)
+			return luaL_error(L, "Need at least two vertices to draw a line");
+
+		float* coords = new float[args];
+		if (is_table) {
+			for (int i = 0; i < args; ++i) {
+				lua_pushnumber(L, i + 1);
+				lua_rawget(L, 1);
+				coords[i] = lua_tonumber(L, -1);
+				lua_pop(L, 1);
+			}
 		} else {
-			float x1 = (float)luaL_checknumber(L, 1);
-			float y1 = (float)luaL_checknumber(L, 2);
-			float x2 = (float)luaL_checknumber(L, 3);
-			float y2 = (float)luaL_checknumber(L, 4);
-			instance->line(x1, y1, x2, y2);
+			for (int i = 0; i < args; ++i)
+				coords[i] = lua_tonumber(L, i + 1);
 		}
+
+		instance->polyline(coords, args);
+
+		delete[] coords;
 		return 0;
 	}
 
@@ -873,7 +871,46 @@ namespace opengl
 
 	int w_polygon(lua_State * L)
 	{
-		return instance->polygon(L);
+		int args = lua_gettop(L) - 1;
+
+		Graphics::DrawMode mode;
+		const char * str = luaL_checkstring(L, 1);
+		if(!Graphics::getConstant(str, mode))
+			return luaL_error(L, "Invalid draw mode: %s", str);
+
+		bool is_table = false;
+		float* coords;
+		if (args == 1 && lua_istable(L, 2)) {
+			args = lua_objlen(L, 2);
+			is_table = true;
+		}
+
+		if (args % 2 != 0)
+			return luaL_error(L, "Number of vertices must be a multiple of two");
+		else if (args < 6)
+			return luaL_error(L, "Need at least three vertices to draw a polygon");
+
+		// fetch coords
+		coords = new float[args + 2];
+		if (is_table) {
+			for (int i = 0; i < args; ++i) {
+				lua_pushnumber(L, i + 1);
+				lua_rawget(L, 2);
+				coords[i] = lua_tonumber(L, -1);
+				lua_pop(L, 1);
+			}
+		} else {
+			for (int i = 0; i < args; ++i)
+				coords[i] = lua_tonumber(L, i + 1);
+		}
+
+		// make a closed loop
+		coords[args]   = coords[0];
+		coords[args+1] = coords[1];
+		instance->polygon(mode, coords, args+2);
+		delete[] coords;
+	
+		return 0;
 	}
 
 	int w_push(lua_State *)
@@ -950,10 +987,8 @@ namespace opengl
 		{ "setLineWidth", w_setLineWidth },
 		{ "setLineStyle", w_setLineStyle },
 		{ "setLine", w_setLine },
-		{ "setLineStipple", w_setLineStipple },
 		{ "getLineWidth", w_getLineWidth },
 		{ "getLineStyle", w_getLineStyle },
-		{ "getLineStipple", w_getLineStipple },
 		{ "setPointSize", w_setPointSize },
 		{ "setPointStyle", w_setPointStyle },
 		{ "setPoint", w_setPoint },