#include "GL/glew.h" #include "hardware_renderer.h" #include #include #include #include #include "triangulation.h" using namespace std; namespace CMU462 { void HardwareRenderer::resize(size_t w, size_t h) { context_w = w; context_h = h; } void HardwareRenderer::begin2DDrawing() { glPushAttrib( GL_VIEWPORT_BIT ); glViewport( 0, 0, context_w, context_h ); glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); glOrtho( 0, context_w, context_h, 0, 0, 1 ); // Y flipped ! glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); glTranslatef( 0, 0, -1 ); } void HardwareRenderer::leave2DDrawing() { glPopAttrib(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); } // Implements SoftwareRenderer // void HardwareRenderer::draw_svg( SVG& svg ) { begin2DDrawing(); // set top level transformation transformation = svg_2_screen; // draw all elements for ( size_t i = 0; i < svg.elements.size(); ++i ) { draw_element(svg.elements[i]); } // draw canvas outline Vector2D a = transform(Vector2D( 0 , 0 )); a.x--; a.y--; Vector2D b = transform(Vector2D(svg.width, 0 )); b.x++; b.y--; Vector2D c = transform(Vector2D( 0 ,svg.height)); c.x--; c.y++; Vector2D d = transform(Vector2D(svg.width,svg.height)); d.x++; d.y++; rasterize_line((float)a.x, (float)a.y, (float)b.x, (float)b.y, Color::Black); rasterize_line((float)a.x, (float)a.y, (float)c.x, (float)c.y, Color::Black); rasterize_line((float)d.x, (float)d.y, (float)b.x, (float)b.y, Color::Black); rasterize_line((float)d.x, (float)d.y, (float)c.x, (float)c.y, Color::Black); leave2DDrawing(); } void HardwareRenderer::draw_element( SVGElement* element ) { // push transformation matrix Matrix3x3 transform_save = transformation; // set object transformation transformation = transformation * element->transform; switch(element->type) { case POINT: draw_point(static_cast(*element)); break; case LINE: draw_line(static_cast(*element)); break; case POLYLINE: draw_polyline(static_cast(*element)); break; case RECT: draw_rect(static_cast(*element)); break; case POLYGON: draw_polygon(static_cast(*element)); break; case ELLIPSE: draw_ellipse(static_cast(*element)); break; case IMAGE: draw_image(static_cast(*element)); break; case GROUP: draw_group(static_cast(*element)); break; default: break; } // pop transformation matrix transformation = transform_save; } // Primitive Drawing // void HardwareRenderer::draw_point( Point& point ) { Vector2D p = transform(point.position); rasterize_point( p.x, p.y, point.style.fillColor ); } void HardwareRenderer::draw_line( Line& line ) { Vector2D p0 = transform(line.from); Vector2D p1 = transform(line.to); rasterize_line( p0.x, p0.y, p1.x, p1.y, line.style.strokeColor ); } void HardwareRenderer::draw_polyline( Polyline& polyline ) { Color c = polyline.style.strokeColor; if( c.a != 0 ) { int nPoints = polyline.points.size(); for( int i = 0; i < nPoints - 1; i++ ) { Vector2D p0 = transform(polyline.points[(i+0) % nPoints]); Vector2D p1 = transform(polyline.points[(i+1) % nPoints]); rasterize_line( p0.x, p0.y, p1.x, p1.y, c ); } } } void HardwareRenderer::draw_rect( Rect& rect ) { Color c; // draw as two triangles float x = rect.position.x; float y = rect.position.y; float w = rect.dimension.x; float h = rect.dimension.y; Vector2D p0 = transform(Vector2D( x , y )); Vector2D p1 = transform(Vector2D( x + w , y )); Vector2D p2 = transform(Vector2D( x , y + h )); Vector2D p3 = transform(Vector2D( x + w , y + h )); // draw fill c = rect.style.fillColor; if (c.a != 0 ) { rasterize_triangle( p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, c ); rasterize_triangle( p2.x, p2.y, p1.x, p1.y, p3.x, p3.y, c ); } // draw outline c = rect.style.strokeColor; if( c.a != 0 ) { rasterize_line( p0.x, p0.y, p1.x, p1.y, c ); rasterize_line( p1.x, p1.y, p3.x, p3.y, c ); rasterize_line( p3.x, p3.y, p2.x, p2.y, c ); rasterize_line( p2.x, p2.y, p0.x, p0.y, c ); } } void HardwareRenderer::draw_polygon( Polygon& polygon ) { Color c; // draw fill c = polygon.style.fillColor; if( c.a != 0 ) { // triangulate vector triangles; triangulate( polygon, triangles ); // draw as triangles for (size_t i = 0; i < triangles.size(); i += 3) { Vector2D p0 = transform(triangles[i + 0]); Vector2D p1 = transform(triangles[i + 1]); Vector2D p2 = transform(triangles[i + 2]); rasterize_triangle( p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, c ); } } // draw outline c = polygon.style.strokeColor; if( c.a != 0 ) { int nPoints = polygon.points.size(); for( int i = 0; i < nPoints; i++ ) { Vector2D p0 = transform(polygon.points[(i+0) % nPoints]); Vector2D p1 = transform(polygon.points[(i+1) % nPoints]); rasterize_line( p0.x, p0.y, p1.x, p1.y, c ); } } } void HardwareRenderer::draw_ellipse( Ellipse& ellipse ) { // TODO } void HardwareRenderer::draw_image( Image& image ) { Vector2D p0 = transform(image.position); Vector2D p1 = transform(image.position + image.dimension); rasterize_image( p0.x, p0.y, p1.x, p1.y, image.tex ); } void HardwareRenderer::draw_group( Group& group ) { for ( size_t i = 0; i < group.elements.size(); ++i ) { draw_element(group.elements[i]); } } // Rasterization // void HardwareRenderer::rasterize_point(float x, float y, Color color) { // Task 1: // Implement point rasterization } void HardwareRenderer::rasterize_line(float x0, float y0, float x1, float y1, Color color) { // Task 1: // Implement line rasterization } void HardwareRenderer::rasterize_triangle(float x0, float y0, float x1, float y1, float x2, float y2, Color color) { // Task 1: // Implement triangle rasterization } void HardwareRenderer::rasterize_image(float x0, float y0, float x1, float y1, Texture& tex) { glColor4f(1, 1, 1, 1); size_t w = tex.mipmap[0].width; size_t h = tex.mipmap[0].height; unsigned char* texels = &tex.mipmap[0].texels[0]; GLuint texid; glGenTextures(1, &texid); glBindTexture(GL_TEXTURE_2D, texid); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // create texture and mipmap glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels); glGenerateMipmap(GL_TEXTURE_2D); // enable texture and draw glEnable(GL_TEXTURE_2D); glBegin(GL_QUADS); glTexCoord2f(0.0, 1.0); glVertex2f( x0, y1 ); glTexCoord2f(1.0, 1.0); glVertex2f( x1, y1 ); glTexCoord2f(1.0, 0.0); glVertex2f( x1, y0 ); glTexCoord2f(0.0, 0.0); glVertex2f( x0, y0 ); glEnd(); glDisable(GL_TEXTURE_2D); return; } } // namespace CMU462