2014-06-05 15:12:49 +00:00
|
|
|
#include "Rasterizer.h"
|
|
|
|
|
2015-12-08 23:32:29 +00:00
|
|
|
#include <cmath>
|
2014-06-12 15:45:59 +00:00
|
|
|
#include "SoftwareRenderer.h"
|
|
|
|
#include "CameraDefinition.h"
|
|
|
|
#include "CanvasPortion.h"
|
|
|
|
#include "CanvasFragment.h"
|
|
|
|
#include "Vector3.h"
|
2015-08-23 18:22:37 +00:00
|
|
|
#include "RenderProgress.h"
|
2014-06-12 15:45:59 +00:00
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
struct paysages::software::ScanPoint {
|
2014-06-12 15:45:59 +00:00
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
struct {
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z;
|
|
|
|
} pixel;
|
|
|
|
struct {
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
double z;
|
|
|
|
} location;
|
2015-12-14 21:20:28 +00:00
|
|
|
unsigned short client;
|
2015-10-15 22:51:46 +00:00
|
|
|
bool front_facing;
|
2014-06-12 15:45:59 +00:00
|
|
|
};
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
struct paysages::software::RenderScanlines {
|
|
|
|
ScanPoint *up;
|
|
|
|
ScanPoint *down;
|
2014-06-12 15:45:59 +00:00
|
|
|
int left;
|
|
|
|
int right;
|
|
|
|
};
|
|
|
|
|
2015-12-14 21:20:28 +00:00
|
|
|
Rasterizer::Rasterizer(SoftwareRenderer *renderer, RenderProgress *progress, unsigned short client_id, const Color &color)
|
2015-11-09 21:30:46 +00:00
|
|
|
: renderer(renderer), progress(progress), client_id(client_id) {
|
2014-08-16 11:34:55 +00:00
|
|
|
this->color = new Color(color);
|
2014-08-19 07:18:55 +00:00
|
|
|
|
|
|
|
interrupted = false;
|
2015-10-15 22:51:46 +00:00
|
|
|
backface_culling = false;
|
2015-11-09 23:34:19 +00:00
|
|
|
perspective_correction = true;
|
2015-10-08 17:20:44 +00:00
|
|
|
triangle_count = 0;
|
|
|
|
auto_cut_limit = 0.01;
|
2015-09-10 17:33:52 +00:00
|
|
|
|
|
|
|
setQuality(0.5);
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
Rasterizer::~Rasterizer() {
|
2014-08-16 11:34:55 +00:00
|
|
|
delete color;
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::interrupt() {
|
2014-08-19 07:18:55 +00:00
|
|
|
interrupted = true;
|
|
|
|
}
|
|
|
|
|
2015-11-09 23:34:19 +00:00
|
|
|
void Rasterizer::setQuality(double quality) {
|
|
|
|
this->perspective_correction = (quality > 0.4);
|
2015-09-10 17:33:52 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::setColor(const Color &color) {
|
2015-10-15 22:51:46 +00:00
|
|
|
*this->color = color;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::setBackFaceCulling(bool cull) {
|
2015-10-15 22:51:46 +00:00
|
|
|
this->backface_culling = cull;
|
|
|
|
}
|
|
|
|
|
2015-11-09 23:34:19 +00:00
|
|
|
void Rasterizer::setPerspectiveCorrection(bool active) {
|
|
|
|
this->perspective_correction = active;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::setAutoCutLimit(double limit) {
|
2015-10-08 17:20:44 +00:00
|
|
|
this->auto_cut_limit = limit;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::resetTriangleCount() {
|
2015-10-08 17:20:44 +00:00
|
|
|
triangle_count = 0;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
bool Rasterizer::pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2,
|
|
|
|
const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2,
|
|
|
|
const Vector3 &location3) {
|
2014-06-12 15:45:59 +00:00
|
|
|
ScanPoint point1, point2, point3;
|
|
|
|
double limit_width = (double)(canvas->getWidth() - 1);
|
|
|
|
double limit_height = (double)(canvas->getHeight() - 1);
|
|
|
|
|
2014-08-18 15:33:15 +00:00
|
|
|
Vector3 canvas_offset(canvas->getXOffset(), canvas->getYOffset(), 0.0);
|
|
|
|
Vector3 dpixel1 = pixel1.sub(canvas_offset);
|
|
|
|
Vector3 dpixel2 = pixel2.sub(canvas_offset);
|
|
|
|
Vector3 dpixel3 = pixel3.sub(canvas_offset);
|
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
double limit_near = renderer->render_camera->getPerspective().znear;
|
2015-11-09 21:30:46 +00:00
|
|
|
if ((dpixel1.z < limit_near && dpixel2.z < limit_near && dpixel3.z < limit_near) ||
|
|
|
|
(dpixel1.x < 0.0 && dpixel2.x < 0.0 && dpixel3.x < 0.0) ||
|
|
|
|
(dpixel1.y < 0.0 && dpixel2.y < 0.0 && dpixel3.y < 0.0) ||
|
|
|
|
(dpixel1.x > limit_width && dpixel2.x > limit_width && dpixel3.x > limit_width) ||
|
|
|
|
(dpixel1.y > limit_height && dpixel2.y > limit_height && dpixel3.y > limit_height)) {
|
2015-10-08 17:20:44 +00:00
|
|
|
// Fully outside screen
|
|
|
|
return false;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (dpixel1.z < limit_near || dpixel2.z < limit_near || dpixel3.z < limit_near) {
|
2015-10-08 17:20:44 +00:00
|
|
|
// Intersects the near frustum plane, needs cutting
|
|
|
|
// ... except if the triangle is already small
|
2015-11-09 21:30:46 +00:00
|
|
|
return location1.sub(location2).getNorm() > auto_cut_limit &&
|
|
|
|
location2.sub(location3).getNorm() > auto_cut_limit &&
|
|
|
|
location3.sub(location1).getNorm() > auto_cut_limit;
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-10-15 22:51:46 +00:00
|
|
|
// Check the poylgon's facing (front-face or back-face)
|
|
|
|
Vector3 normal = dpixel2.sub(dpixel1).crossProduct(dpixel3.sub(dpixel1));
|
|
|
|
bool front_facing = (normal.z >= 0.0);
|
2015-11-09 21:30:46 +00:00
|
|
|
if (backface_culling and not front_facing) {
|
2015-10-15 22:51:46 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
// Prepare vertices
|
2014-08-18 15:33:15 +00:00
|
|
|
point1.pixel.x = dpixel1.x;
|
|
|
|
point1.pixel.y = dpixel1.y;
|
|
|
|
point1.pixel.z = dpixel1.z;
|
2014-06-12 15:45:59 +00:00
|
|
|
point1.location.x = location1.x;
|
|
|
|
point1.location.y = location1.y;
|
|
|
|
point1.location.z = location1.z;
|
|
|
|
point1.client = client_id;
|
2015-10-15 22:51:46 +00:00
|
|
|
point1.front_facing = front_facing;
|
2014-06-12 15:45:59 +00:00
|
|
|
|
2014-08-18 15:33:15 +00:00
|
|
|
point2.pixel.x = dpixel2.x;
|
|
|
|
point2.pixel.y = dpixel2.y;
|
|
|
|
point2.pixel.z = dpixel2.z;
|
2014-06-12 15:45:59 +00:00
|
|
|
point2.location.x = location2.x;
|
|
|
|
point2.location.y = location2.y;
|
|
|
|
point2.location.z = location2.z;
|
|
|
|
point2.client = client_id;
|
2015-10-15 22:51:46 +00:00
|
|
|
point2.front_facing = front_facing;
|
2014-06-12 15:45:59 +00:00
|
|
|
|
2014-08-18 15:33:15 +00:00
|
|
|
point3.pixel.x = dpixel3.x;
|
|
|
|
point3.pixel.y = dpixel3.y;
|
|
|
|
point3.pixel.z = dpixel3.z;
|
2014-06-12 15:45:59 +00:00
|
|
|
point3.location.x = location3.x;
|
|
|
|
point3.location.y = location3.y;
|
|
|
|
point3.location.z = location3.z;
|
|
|
|
point3.client = client_id;
|
2015-10-15 22:51:46 +00:00
|
|
|
point3.front_facing = front_facing;
|
2014-06-12 15:45:59 +00:00
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
// Prepare scanlines
|
2014-06-12 15:45:59 +00:00
|
|
|
// TODO Don't create scanlines for each triangles (one by thread is more appropriate)
|
|
|
|
RenderScanlines scanlines;
|
|
|
|
int width = canvas->getWidth();
|
|
|
|
scanlines.left = width;
|
|
|
|
scanlines.right = -1;
|
|
|
|
scanlines.up = new ScanPoint[width];
|
|
|
|
scanlines.down = new ScanPoint[width];
|
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
// Render edges in scanlines
|
2014-06-12 15:45:59 +00:00
|
|
|
pushScanLineEdge(canvas, &scanlines, &point1, &point2);
|
|
|
|
pushScanLineEdge(canvas, &scanlines, &point2, &point3);
|
|
|
|
pushScanLineEdge(canvas, &scanlines, &point3, &point1);
|
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
// Commit scanlines to area
|
2014-06-12 15:45:59 +00:00
|
|
|
renderScanLines(canvas, &scanlines);
|
|
|
|
|
2015-10-08 17:20:44 +00:00
|
|
|
// Free scalines
|
2014-06-12 15:45:59 +00:00
|
|
|
delete[] scanlines.up;
|
|
|
|
delete[] scanlines.down;
|
2015-10-08 17:20:44 +00:00
|
|
|
|
|
|
|
triangle_count++;
|
|
|
|
return false;
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::pushTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) {
|
2014-06-12 15:45:59 +00:00
|
|
|
Vector3 p1, p2, p3;
|
|
|
|
|
|
|
|
p1 = getRenderer()->projectPoint(v1);
|
|
|
|
p2 = getRenderer()->projectPoint(v2);
|
|
|
|
p3 = getRenderer()->projectPoint(v3);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (pushProjectedTriangle(canvas, p1, p2, p3, v1, v2, v3)) {
|
2015-10-08 17:20:44 +00:00
|
|
|
// Cutting needed
|
|
|
|
Vector3 vm1 = v1.midPointTo(v2);
|
|
|
|
Vector3 vm2 = v2.midPointTo(v3);
|
|
|
|
Vector3 vm3 = v3.midPointTo(v1);
|
|
|
|
pushTriangle(canvas, v1, vm1, vm3);
|
|
|
|
pushTriangle(canvas, v2, vm1, vm2);
|
|
|
|
pushTriangle(canvas, v3, vm3, vm2);
|
|
|
|
pushTriangle(canvas, vm1, vm2, vm3);
|
|
|
|
}
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::pushDisplacedTriangle(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3,
|
|
|
|
const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3) {
|
2014-06-12 15:45:59 +00:00
|
|
|
Vector3 p1, p2, p3;
|
|
|
|
|
2015-10-15 22:51:46 +00:00
|
|
|
// TODO v1, v2 and v3 are lost, but may be useful (avoid need to unproject)
|
2014-06-12 15:45:59 +00:00
|
|
|
p1 = getRenderer()->projectPoint(v1);
|
|
|
|
p2 = getRenderer()->projectPoint(v2);
|
|
|
|
p3 = getRenderer()->projectPoint(v3);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (pushProjectedTriangle(canvas, p1, p2, p3, ov1, ov2, ov3)) {
|
2015-10-08 17:20:44 +00:00
|
|
|
// Cutting needed
|
|
|
|
Vector3 vm1 = v1.midPointTo(v2);
|
|
|
|
Vector3 vm2 = v2.midPointTo(v3);
|
|
|
|
Vector3 vm3 = v3.midPointTo(v1);
|
|
|
|
Vector3 ovm1 = ov1.midPointTo(ov2);
|
|
|
|
Vector3 ovm2 = ov2.midPointTo(ov3);
|
|
|
|
Vector3 ovm3 = ov3.midPointTo(ov1);
|
|
|
|
pushDisplacedTriangle(canvas, v1, vm1, vm3, ov1, ovm1, ovm3);
|
|
|
|
pushDisplacedTriangle(canvas, v2, vm1, vm2, ov2, ovm1, ovm2);
|
|
|
|
pushDisplacedTriangle(canvas, v3, vm3, vm2, ov3, ovm3, ovm2);
|
|
|
|
pushDisplacedTriangle(canvas, vm1, vm2, vm3, ovm1, ovm2, ovm3);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::pushQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3,
|
|
|
|
const Vector3 &v4) {
|
2015-10-08 17:20:44 +00:00
|
|
|
pushTriangle(canvas, v2, v3, v1);
|
|
|
|
pushTriangle(canvas, v4, v1, v3);
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::pushDisplacedQuad(CanvasPortion *canvas, const Vector3 &v1, const Vector3 &v2, const Vector3 &v3,
|
|
|
|
const Vector3 &v4, const Vector3 &ov1, const Vector3 &ov2, const Vector3 &ov3,
|
|
|
|
const Vector3 &ov4) {
|
2014-06-12 15:45:59 +00:00
|
|
|
pushDisplacedTriangle(canvas, v2, v3, v1, ov2, ov3, ov1);
|
|
|
|
pushDisplacedTriangle(canvas, v4, v1, v3, ov4, ov1, ov3);
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::scanGetDiff(ScanPoint *v1, ScanPoint *v2, ScanPoint *result) {
|
2014-06-12 15:45:59 +00:00
|
|
|
result->pixel.x = v2->pixel.x - v1->pixel.x;
|
|
|
|
result->pixel.y = v2->pixel.y - v1->pixel.y;
|
|
|
|
result->pixel.z = v2->pixel.z - v1->pixel.z;
|
|
|
|
result->location.x = v2->location.x - v1->location.x;
|
|
|
|
result->location.y = v2->location.y - v1->location.y;
|
|
|
|
result->location.z = v2->location.z - v1->location.z;
|
|
|
|
result->client = v1->client;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::scanInterpolate(CameraDefinition *camera, ScanPoint *v1, ScanPoint *diff, double value,
|
|
|
|
ScanPoint *result) {
|
2014-06-12 15:45:59 +00:00
|
|
|
result->pixel.x = v1->pixel.x + diff->pixel.x * value;
|
|
|
|
result->pixel.y = v1->pixel.y + diff->pixel.y * value;
|
|
|
|
result->pixel.z = v1->pixel.z + diff->pixel.z * value;
|
2015-11-09 23:34:19 +00:00
|
|
|
|
|
|
|
if (perspective_correction) {
|
|
|
|
Vector3 vec1(v1->pixel.x, v1->pixel.y, v1->pixel.z);
|
|
|
|
Vector3 vecdiff(diff->pixel.x, diff->pixel.y, diff->pixel.z);
|
|
|
|
double v1depth = 1.0 / camera->getRealDepth(vec1);
|
|
|
|
double v2depth = 1.0 / camera->getRealDepth(vec1.add(vecdiff));
|
|
|
|
double factor = 1.0 / ((1.0 - value) * v1depth + value * v2depth);
|
|
|
|
|
|
|
|
result->location.x =
|
|
|
|
((1.0 - value) * (v1->location.x * v1depth) + value * (v1->location.x + diff->location.x) * v2depth) *
|
|
|
|
factor;
|
|
|
|
result->location.y =
|
|
|
|
((1.0 - value) * (v1->location.y * v1depth) + value * (v1->location.y + diff->location.y) * v2depth) *
|
|
|
|
factor;
|
|
|
|
result->location.z =
|
|
|
|
((1.0 - value) * (v1->location.z * v1depth) + value * (v1->location.z + diff->location.z) * v2depth) *
|
|
|
|
factor;
|
|
|
|
} else {
|
|
|
|
result->location.x = v1->location.x + diff->location.x * value;
|
|
|
|
result->location.y = v1->location.y + diff->location.y * value;
|
|
|
|
result->location.z = v1->location.z + diff->location.z * value;
|
|
|
|
}
|
|
|
|
|
2014-06-12 15:45:59 +00:00
|
|
|
result->client = v1->client;
|
2015-10-15 22:51:46 +00:00
|
|
|
result->front_facing = v1->front_facing;
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::pushScanPoint(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point) {
|
2014-06-12 15:45:59 +00:00
|
|
|
point->x = (int)floor(point->pixel.x);
|
|
|
|
point->y = (int)floor(point->pixel.y);
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (point->x < 0 || point->x >= canvas->getWidth()) {
|
2014-06-12 15:45:59 +00:00
|
|
|
// Point outside scanline range
|
|
|
|
return;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (scanlines->right < 0) {
|
2014-06-12 15:45:59 +00:00
|
|
|
// First point pushed
|
|
|
|
scanlines->left = point->x;
|
|
|
|
scanlines->right = point->x;
|
|
|
|
scanlines->up[point->x] = *point;
|
|
|
|
scanlines->down[point->x] = *point;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (point->x > scanlines->right) {
|
2014-06-12 15:45:59 +00:00
|
|
|
// Grow scanlines to right
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int x = scanlines->right + 1; x < point->x; x++) {
|
2014-06-12 15:45:59 +00:00
|
|
|
scanlines->up[x].y = -1;
|
|
|
|
scanlines->down[x].y = canvas->getHeight();
|
|
|
|
}
|
|
|
|
scanlines->right = point->x;
|
|
|
|
scanlines->up[point->x] = *point;
|
|
|
|
scanlines->down[point->x] = *point;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (point->x < scanlines->left) {
|
2014-06-12 15:45:59 +00:00
|
|
|
// Grow scanlines to left
|
2015-11-09 21:30:46 +00:00
|
|
|
for (int x = point->x + 1; x < scanlines->left; x++) {
|
2014-06-12 15:45:59 +00:00
|
|
|
scanlines->up[x].y = -1;
|
|
|
|
scanlines->down[x].y = canvas->getHeight();
|
|
|
|
}
|
|
|
|
scanlines->left = point->x;
|
|
|
|
scanlines->up[point->x] = *point;
|
|
|
|
scanlines->down[point->x] = *point;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2014-06-12 15:45:59 +00:00
|
|
|
// Expand existing scanline
|
2015-11-09 21:30:46 +00:00
|
|
|
if (point->y > scanlines->up[point->x].y) {
|
2014-06-12 15:45:59 +00:00
|
|
|
scanlines->up[point->x] = *point;
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
if (point->y < scanlines->down[point->x].y) {
|
2014-06-12 15:45:59 +00:00
|
|
|
scanlines->down[point->x] = *point;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::pushScanLineEdge(CanvasPortion *canvas, RenderScanlines *scanlines, ScanPoint *point1,
|
|
|
|
ScanPoint *point2) {
|
2014-06-12 15:45:59 +00:00
|
|
|
double dx, fx;
|
|
|
|
ScanPoint diff, point;
|
|
|
|
int startx = lround(point1->pixel.x);
|
|
|
|
int endx = lround(point2->pixel.x);
|
|
|
|
int curx;
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (endx < startx) {
|
2014-06-12 15:45:59 +00:00
|
|
|
pushScanLineEdge(canvas, scanlines, point2, point1);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (endx < 0 || startx >= canvas->getWidth()) {
|
2014-06-12 15:45:59 +00:00
|
|
|
return;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (startx == endx) {
|
2014-06-12 15:45:59 +00:00
|
|
|
pushScanPoint(canvas, scanlines, point1);
|
|
|
|
pushScanPoint(canvas, scanlines, point2);
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
|
|
|
if (startx < 0) {
|
2014-06-12 15:45:59 +00:00
|
|
|
startx = 0;
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
if (endx >= canvas->getWidth()) {
|
2014-06-12 15:45:59 +00:00
|
|
|
endx = canvas->getWidth() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dx = point2->pixel.x - point1->pixel.x;
|
|
|
|
scanGetDiff(point1, point2, &diff);
|
2015-11-09 21:30:46 +00:00
|
|
|
for (curx = startx; curx <= endx; curx++) {
|
2014-06-12 15:45:59 +00:00
|
|
|
fx = (double)curx + 0.5;
|
2015-11-09 21:30:46 +00:00
|
|
|
if (fx < point1->pixel.x) {
|
2014-06-12 15:45:59 +00:00
|
|
|
fx = point1->pixel.x;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (fx > point2->pixel.x) {
|
2014-06-12 15:45:59 +00:00
|
|
|
fx = point2->pixel.x;
|
|
|
|
}
|
|
|
|
fx = fx - point1->pixel.x;
|
|
|
|
scanInterpolate(renderer->render_camera, point1, &diff, fx / dx, &point);
|
|
|
|
|
|
|
|
/*point.pixel.x = (double)curx;*/
|
|
|
|
|
|
|
|
pushScanPoint(canvas, scanlines, &point);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines *scanlines) {
|
2014-06-12 15:45:59 +00:00
|
|
|
int x, starty, endy, cury;
|
|
|
|
ScanPoint diff;
|
|
|
|
double dy, fy;
|
|
|
|
ScanPoint up, down, current;
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (scanlines->right > 0) {
|
|
|
|
for (x = scanlines->left; x <= scanlines->right; x++) {
|
2014-06-12 15:45:59 +00:00
|
|
|
up = scanlines->up[x];
|
|
|
|
down = scanlines->down[x];
|
|
|
|
|
|
|
|
starty = down.y;
|
|
|
|
endy = up.y;
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (endy < 0 || starty >= canvas->getHeight()) {
|
2014-06-12 15:45:59 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
if (starty < 0) {
|
2014-06-12 15:45:59 +00:00
|
|
|
starty = 0;
|
|
|
|
}
|
2015-11-09 21:30:46 +00:00
|
|
|
if (endy >= canvas->getHeight()) {
|
2014-06-12 15:45:59 +00:00
|
|
|
endy = canvas->getHeight() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dy = up.pixel.y - down.pixel.y;
|
|
|
|
scanGetDiff(&down, &up, &diff);
|
|
|
|
|
|
|
|
current.x = x;
|
2015-11-09 21:30:46 +00:00
|
|
|
for (cury = starty; cury <= endy; cury++) {
|
|
|
|
if (dy == 0) {
|
2014-08-18 10:17:16 +00:00
|
|
|
// Down and up are the same
|
|
|
|
current = down;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else {
|
2014-08-18 10:17:16 +00:00
|
|
|
fy = (double)cury + 0.5;
|
2015-11-09 21:30:46 +00:00
|
|
|
if (fy < down.pixel.y) {
|
2014-08-18 10:17:16 +00:00
|
|
|
fy = down.pixel.y;
|
2015-11-09 21:30:46 +00:00
|
|
|
} else if (fy > up.pixel.y) {
|
2014-08-18 10:17:16 +00:00
|
|
|
fy = up.pixel.y;
|
|
|
|
}
|
|
|
|
fy = fy - down.pixel.y;
|
|
|
|
|
|
|
|
current.y = cury;
|
|
|
|
scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t);
|
2014-06-12 15:45:59 +00:00
|
|
|
}
|
|
|
|
|
2015-11-09 21:30:46 +00:00
|
|
|
Vector3 pixel(current.pixel.x + canvas->getXOffset(), current.pixel.y + canvas->getYOffset(),
|
|
|
|
current.pixel.z);
|
2015-10-15 22:51:46 +00:00
|
|
|
Vector3 location(current.location.x, current.location.y, current.location.z);
|
|
|
|
CanvasFragment fragment(current.front_facing, pixel, location, current.client, color->a == 1.0);
|
2014-08-16 11:34:55 +00:00
|
|
|
|
|
|
|
Color frag_color = *color;
|
2015-10-15 22:51:46 +00:00
|
|
|
frag_color.a = 1.0;
|
2015-11-09 21:30:46 +00:00
|
|
|
if (cury == starty || cury == endy) {
|
2014-08-18 14:33:09 +00:00
|
|
|
frag_color.mask(Color(0.0, 0.0, 0.0, 0.3));
|
2014-08-18 10:17:16 +00:00
|
|
|
}
|
2015-10-15 22:51:46 +00:00
|
|
|
frag_color.a = color->a;
|
2014-08-16 11:34:55 +00:00
|
|
|
fragment.setColor(frag_color);
|
|
|
|
|
2014-06-12 15:45:59 +00:00
|
|
|
canvas->pushFragment(current.x, current.y, fragment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-06-05 15:12:49 +00:00
|
|
|
}
|