Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "software_renderer.h"
- #include <cmath>
- #include <vector>
- #include <iostream>
- #include <algorithm>
- #include "triangulation.h"
- using namespace std;
- namespace CS248 {
- // Implements SoftwareRenderer //
- // fill a sample location with color
- void SoftwareRendererImp::fill_sample(int sx, int sy, const Color &color) {
- // cerr << "in fill sample\n";
- if (sx < 0 || sx >= target_w * sample_rate) return;
- if (sy < 0 || sy >= target_h * sample_rate) return;
- Color pixel_color;
- float inv255 = 1.0 / 255.0;
- pixel_color.r = sample_buffer[4 * (sx + sy * target_w * sample_rate)] * inv255;
- pixel_color.g = sample_buffer[4 * (sx + sy * target_w * sample_rate) + 1] * inv255;
- pixel_color.b = sample_buffer[4 * (sx + sy * target_w * sample_rate) + 2] * inv255;
- pixel_color.a = sample_buffer[4 * (sx + sy * target_w * sample_rate) + 3] * inv255;
- //cerr << pixel_color << endl;
- pixel_color = ref->alpha_blending_helper(pixel_color, color);
- //cerr << "original pixel color" << pixel_color << endl;
- // cerr << "sx " << sx << "sy " << sy << "target_w" << target_w << "sample rate " << sample_rate << endl;
- // cerr << "index " << 4 * (sx + sy * target_w * sample_rate) << endl;
- sample_buffer[4 * (sx + sy * target_w * sample_rate)] = (uint8_t)(pixel_color.r * 255);
- // cerr << "doen with r\n";
- sample_buffer[4 * (sx + sy * target_w * sample_rate) + 1] = (uint8_t)(pixel_color.g * 255);
- // cerr << "doen with g\n";
- sample_buffer[4 * (sx + sy * target_w * sample_rate) + 2] = (uint8_t)(pixel_color.b * 255);
- // cerr << "doen with b\n";
- sample_buffer[4 * (sx + sy * target_w * sample_rate) + 3] = (uint8_t)(pixel_color.a * 255);
- }
- // fill samples in the entire pixel specified by pixel coordinates
- void SoftwareRendererImp::fill_pixel(int x, int y, const Color &color) {
- // Task 2: Re-implement this function
- // check bounds
- if (x < 0 || x >= target_w) return;
- if (y < 0 || y >= target_h) return;
- for (size_t sx = 0; sx < sample_rate; sx++)
- {
- for (size_t sy = 0; sy < sample_rate; sy++)
- {
- fill_sample(x * sample_rate + sx, y * sample_rate + sy, color);
- }
- }
- }
- void SoftwareRendererImp::draw_svg( SVG& svg ) {
- // set top level transformation
- transformation = canvas_to_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(a.x, a.y, b.x, b.y, Color::Black);
- rasterize_line(a.x, a.y, c.x, c.y, Color::Black);
- rasterize_line(d.x, d.y, b.x, b.y, Color::Black);
- rasterize_line(d.x, d.y, c.x, c.y, Color::Black);
- // resolve and send to render target
- resolve();
- }
- void SoftwareRendererImp::set_sample_rate( size_t sample_rate ) {
- cerr << "set sampler ate called" << endl << endl << endl << endl << endl;
- this->sample_rate = sample_rate;
- size_t sample_buffer_size = 4 * target_h * target_w * sample_rate * sample_rate;
- this->sample_buffer.reserve(sample_buffer_size);
- for (size_t i = 0; i < sample_buffer_size; i++) sample_buffer[i] = (uint8_t) 255;
- }
- void SoftwareRendererImp::set_render_target( unsigned char* render_target,
- size_t width, size_t height ) {
- this->render_target = render_target;
- this->target_w = width;
- this->target_h = height;
- size_t sample_buffer_size = 4 * target_h * target_w * sample_rate * sample_rate;
- this->sample_buffer.reserve(sample_buffer_size);
- for (size_t i = 0; i < sample_buffer_size; i++) sample_buffer[i] = (uint8_t) 255;
- }
- void SoftwareRendererImp::draw_element( SVGElement* element ) {
- // Task 3 (part 1):
- // Modify this to implement the transformation stack
- Matrix3x3 oldTrans = transformation;
- transformation = transformation * element->transform;
- switch (element->type) {
- case POINT:
- draw_point(static_cast<Point&>(*element));
- break;
- case LINE:
- draw_line(static_cast<Line&>(*element));
- break;
- case POLYLINE:
- draw_polyline(static_cast<Polyline&>(*element));
- break;
- case RECT:
- draw_rect(static_cast<Rect&>(*element));
- break;
- case POLYGON:
- draw_polygon(static_cast<Polygon&>(*element));
- break;
- case ELLIPSE:
- draw_ellipse(static_cast<Ellipse&>(*element));
- break;
- case IMAGE:
- draw_image(static_cast<Image&>(*element));
- break;
- case GROUP:
- draw_group(static_cast<Group&>(*element));
- break;
- default:
- break;
- }
- transformation = oldTrans;
- }
- // Primitive Drawing //
- void SoftwareRendererImp::draw_point( Point& point ) {
- Vector2D p = transform(point.position);
- rasterize_point( p.x, p.y, point.style.fillColor );
- }
- void SoftwareRendererImp::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 SoftwareRendererImp::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 SoftwareRendererImp::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 SoftwareRendererImp::draw_polygon( Polygon& polygon ) {
- Color c;
- // draw fill
- c = polygon.style.fillColor;
- if( c.a != 0 ) {
- // triangulate
- vector<Vector2D> 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 SoftwareRendererImp::draw_ellipse( Ellipse& ellipse ) {
- // Extra credit
- }
- void SoftwareRendererImp::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 SoftwareRendererImp::draw_group( Group& group ) {
- for ( size_t i = 0; i < group.elements.size(); ++i ) {
- draw_element(group.elements[i]);
- }
- }
- // Rasterization //
- // The input arguments in the rasterization functions
- // below are all defined in screen space coordinates
- void SoftwareRendererImp::rasterize_point( float x, float y, Color color ) {
- // fill in the nearest pixel
- int sx = (int)floor(x);
- int sy = (int)floor(y);
- // check bounds
- if (sx < 0 || sx >= target_w) return;
- if (sy < 0 || sy >= target_h) return;
- fill_pixel(sx, sy, color);
- }
- void SoftwareRendererImp::rasterize_line( float x0, float y0,
- float x1, float y1,
- Color color) {
- // Extra credit (delete the line below and implement your own)
- ref->rasterize_line_helper(x0, y0, x1, y1, target_w, target_h, color, this);
- }
- int findMaxIdx(const float vals[]) {
- int numElems = 3;
- int maxSoFar = 0;
- for (int i = 0; i < numElems; i++)
- if (vals[maxSoFar] < vals[i]) maxSoFar = i;
- return maxSoFar;
- }
- int findMinIdx(const float vals[]) {
- int numElems = 3;
- int minSoFar = 0;
- for (int i = 0; i < numElems; i++)
- if (vals[minSoFar] > vals[i]) minSoFar = i;
- return minSoFar;
- }
- void getCounterCPoints(const float xVals[], const float yVals[], float xCCW[], float yCCW[])
- {
- int lIdx = findMinIdx(xVals);
- int rIdx = findMaxIdx(xVals);
- int oIdx = 3 - lIdx - rIdx;
- Vector2D normalVec = Vector2D(yVals[rIdx] - yVals[lIdx], - (xVals[rIdx] - xVals[lIdx]));
- Vector2D toCheckVec = Vector2D(xVals[oIdx] - xVals[lIdx], yVals[oIdx] - yVals[lIdx]);
- double d = dot(toCheckVec.unit(), normalVec.unit());
- if (d > 0) {
- xCCW[0] = xVals[lIdx];
- xCCW[1] = xVals[rIdx];
- xCCW[2] = xVals[oIdx];
- yCCW[0] = yVals[lIdx];
- yCCW[1] = yVals[rIdx];
- yCCW[2] = yVals[oIdx];
- } else {
- xCCW[0] = xVals[lIdx];
- xCCW[1] = xVals[oIdx];
- xCCW[2] = xVals[rIdx];
- yCCW[0] = yVals[lIdx];
- yCCW[1] = yVals[oIdx];
- yCCW[2] = yVals[rIdx];
- }
- }
- // http://totologic.blogspot.com/2014/01/accurate-point-in-triangle-test.html
- bool isInsideTri(const double &x, const double &y, const float xCCW[], const float yCCW[])
- {
- Vector2D v0 = (Vector2D(yCCW[1] - yCCW[0], -xCCW[1] + xCCW[0])).unit();
- Vector2D v1 = (Vector2D(yCCW[2] - yCCW[1], -xCCW[2] + xCCW[1])).unit();
- Vector2D v2 = (Vector2D(yCCW[0] - yCCW[2], -xCCW[0] + xCCW[2])).unit();
- Vector2D v0p = (Vector2D(x - xCCW[0], y - yCCW[0])).unit();
- Vector2D v1p = (Vector2D(x - xCCW[1], y - yCCW[1])).unit();
- Vector2D v2p = (Vector2D(x - xCCW[2], y - yCCW[2])).unit();
- double d0 = dot(v0, v0p);
- double d1 = dot(v1, v1p);
- double d2 = dot(v2, v2p);
- return (d0 >= 0 && d1 >= 0 && d2 >= 0);
- }
- void SoftwareRendererImp::rasterize_triangle( float x0, float y0,
- float x1, float y1,
- float x2, float y2,
- Color color ) {
- float xVals[3] = {x0, x1, x2};
- float yVals[3] = {y0, y1, y2};
- float xCCW[3], yCCW[3];
- // Get points in counter clockwise order
- getCounterCPoints(xVals, yVals, xCCW, yCCW);
- // Get bounding box
- int minX = floor(min({x0, x1, x2}));
- int maxX = floor(max({x0, x1, x2}));
- int minY = floor(min({y0, y1, y2}));
- int maxY = floor(max({y0, y1, y2}));
- for (int sx = minX * sample_rate; sx <= maxX * sample_rate; sx++)
- {
- for (int sy = minY * sample_rate; sy <= maxY * sample_rate; sy++)
- {
- if (isInsideTri((double)sx / (double)sample_rate + 1.0 / (double) (2 * sample_rate), (double)sy / (double)sample_rate + 1.0 / (double) (2 * sample_rate), xCCW, yCCW))
- fill_sample(sx, sy, color);
- }
- }
- }
- void SoftwareRendererImp::rasterize_image( float x0, float y0,
- float x1, float y1,
- Texture& tex ) {
- // Task 4:
- // Implement image rasterization (you may want to call fill_sample here)
- int minx = floor(x0);
- int maxx = floor(x1);
- int miny = floor(y0);
- int maxy = floor(y1);
- float width = x1 - x0;
- float height = y1 - y0;
- for (float x = minx; x < maxx; x++)
- {
- for (floor y = miny; y < maxy; y++)
- {
- sampler->sample_nearest(tex, x / wdith, y / height);
- }
- }
- }
- // resolve samples to render target
- void SoftwareRendererImp::resolve( void ) {
- for (unsigned x = 0; x < target_w; x++)
- {
- for (unsigned y = 0; y < target_h; y++)
- {
- Color total(0.0, 0.0, 0.0, 0.0);
- for (unsigned sx = x * sample_rate; sx < (x + 1) * sample_rate; sx++)
- {
- for (unsigned sy = y * sample_rate; sy < (y + 1) * sample_rate; sy++)
- {
- Color c;
- float inv255 = 1.0 / 255.0;
- c.r = sample_buffer[4 * (sx + sy * target_w * sample_rate)] * inv255;
- c.g = sample_buffer[4 * (sx + sy * target_w * sample_rate) + 1] * inv255;
- c.b = sample_buffer[4 * (sx + sy * target_w * sample_rate) + 2] * inv255;
- c.a = sample_buffer[4 * (sx + sy * target_w * sample_rate) + 3] * inv255;
- total += c;
- //cerr << "temp total" << total << endl;
- }
- }
- total *= 1.0 / ((float) (sample_rate * sample_rate));
- //if(total.r > 0.1) cerr << "total " << total << endl;
- render_target[4 * (x + y * target_w)] = (uint8_t)(total.r * 255);
- render_target[4 * (x + y * target_w) + 1] = (uint8_t)(total.g * 255);
- render_target[4 * (x + y * target_w) + 2] = (uint8_t)(total.b * 255);
- render_target[4 * (x + y * target_w) + 3] = (uint8_t)(total.a * 255);
- }
- }
- size_t sample_buffer_size = 4 * target_h * target_w * sample_rate * sample_rate;
- for (size_t i = 0; i < sample_buffer_size; i++)
- {
- sample_buffer[i] = (uint8_t) 255;
- }
- }
- } // namespace CS248
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement