diff --git a/src/rendering/rasterize.c b/src/rendering/rasterize.c new file mode 100644 index 0000000000000000000000000000000000000000..ecf1f4845ed805a6ae418b06670f7dd523f27e07 --- /dev/null +++ b/src/rendering/rasterize.c @@ -0,0 +1,274 @@ +#include "rasterize.h" + +inline float removeSign(float f){ + if(f<0) + return 0; + return f; +} + +_2x1Matrix transpose_map(_3x3Matrix m1, _3x1Matrix m2){ + _2x1Matrix ma = { + (m1.a11 * m2.a11) + (m1.a12 * m2.a21) + (m1.a13 * m2.a31), + (m1.a21 * m2.a11) + (m1.a22 * m2.a21) + (m1.a23 * m2.a31), + }; + + return ma; +} + +rectangle getXYBound2d(tri2d t){ + uint16_t xHigh = (uint16_t)fmax(fmax(t.p0.a11,t.p1.a11),t.p2.a11); + uint16_t xLow = (uint16_t)fmin(fmin(t.p0.a11,t.p1.a11),t.p2.a11); + uint16_t yHigh = (uint16_t)fmax(fmax(t.p0.a21,t.p1.a21),t.p2.a21); + uint16_t yLow = (uint16_t)fmin(fmin(t.p0.a21,t.p1.a21),t.p2.a21); + + rectangle r = {xLow, xHigh+1, yLow, yHigh+1}; + return r; +} + +rectangle getXYBound2dRect(rect2d t){ + uint16_t xLow = (uint16_t)fmin(fmin(fmin(removeSign(t.p0.a11),removeSign(t.p1.a11)), + removeSign(t.p2.a11)),removeSign(t.p3.a11)); + uint16_t xHigh = (uint16_t)fmax(fmax(fmax(removeSign(t.p0.a11),removeSign(t.p1.a11)), + removeSign(t.p2.a11)),removeSign(t.p3.a11)); + uint16_t yLow = (uint16_t)fmin(fmin(fmin(removeSign(t.p0.a21),removeSign(t.p1.a21)), + removeSign(t.p2.a21)),removeSign(t.p3.a21)); + uint16_t yHigh = (uint16_t)fmax(fmax(fmax(removeSign(t.p0.a21),removeSign(t.p1.a21)), + removeSign(t.p2.a21)),removeSign(t.p3.a21)); + + rectangle r = {xLow, xHigh+1, yLow, yHigh+1}; + return r; +} + +rectangle getXYBound3d(tri3d t){ + uint16_t xHigh = (uint16_t)fmax(fmax(removeSign(t.p0.a11),removeSign(t.p1.a11)),removeSign(t.p2.a11)); + uint16_t xLow = (uint16_t)fmin(fmin(removeSign(t.p0.a11),removeSign(t.p1.a11)),removeSign(t.p2.a11)); + uint16_t yHigh = (uint16_t)fmax(fmax(removeSign(t.p0.a21),removeSign(t.p1.a21)),removeSign(t.p2.a21)); + uint16_t yLow = (uint16_t)fmin(fmin(removeSign(t.p0.a21),removeSign(t.p1.a21)),removeSign(t.p2.a21)); + + rectangle r = {xLow, xHigh+1, yLow, yHigh+1}; + return r; +} + +void affineRasterize(_2x2Matrix m, PGM_P imgdata, rectangle imgRegion, int16_t dispX, int16_t dispY){ //Rectangle affine without Composites + rect2d t = {{imgRegion.left, imgRegion.top}, {imgRegion.right, imgRegion.top}, + {imgRegion.right, imgRegion.bottom}, {imgRegion.left, imgRegion.bottom}}; + _2x2Matrix invM = inverse_2x2(m); + rect2d tP = transpose2dRect(t, m); + + rectangle r = getXYBound2dRect(tP); + r.bottom = removeSign((((int16_t) r.bottom) + dispY)); + r.right = removeSign((((int16_t) r.right) + dispX)); + + uint16_t imgwidth = imgRegion.right-imgRegion.left; + uint16_t imgheight = imgRegion.bottom-imgRegion.top; + rectangleInRegion(&r); + int16_t width = r.right - r.left; + int16_t height = r.bottom - r.top; + + char* targetptr = imgdata; + setupDraw(r); + uint16_t pixVal; + + for(int16_t y=-dispY; y<=height-dispY; y++) + for(int16_t x=-dispX; x<=width-dispX; x++){ + _2x1Matrix p = {x,y}; + _2x1Matrix pT = transpose_2x2(invM, p); + if(pT.a11 >= 0 && pT.a11 <= imgwidth + && pT.a21 >= 0 && pT.a21 <= imgheight){ + uint16_t xComp = (uint16_t) (removeSign(pT.a11)); + uint16_t yComp = (uint16_t) (removeSign(pT.a21)); + targetptr = imgdata + (2*(xComp+(yComp*(imgwidth+1)))); + pixVal = pgm_read_word(targetptr); + } else { + pixVal = 0; + } + write_data16(pixVal); + } +} + +void perspectiveRasterize(tri3d t, tri2d tuv, PGM_P imgdata, rectangle imgRegion) { + _3x3Matrix triangleMat = combine(t.p0, t.p1, t.p2); + _3x3Matrix uvMat = combine2d(tuv.p0, tuv.p1, tuv.p2); + _3x3Matrix invMTM = inverse_3x3(triangleMat); + _3x3Matrix mapping = multiply_3x3(uvMat, invMTM); + plane3d pl = getPlane(t); + + rectangle r = getXYBound3d(t); + uint16_t imgwidth = imgRegion.right-imgRegion.left; + uint16_t imgheight = imgRegion.bottom-imgRegion.top; + rectangleInRegion(&r); + uint16_t width = r.right - r.left; + uint16_t height = r.bottom - r.top; + + tri2d t2d = {{t.p0.a11,t.p0.a21}, + {t.p1.a11,t.p1.a21}, + {t.p2.a11,t.p2.a21}}; + + char* targetptr = imgdata; + setupDraw(r); + uint16_t pixVal; + + for (uint16_t y = r.top; y <= r.bottom; y++) { + for (uint16_t x = r.left; x <= r.right; x++) { + _2x1Matrix point = {x, y}; + _2x1Matrix tPoint = transpose_2x3(mapping, point); + if(inTriangle(tPoint.a11, tPoint.a21, tuv)){ + uint16_t xComp = (uint16_t) (removeSign(tPoint.a11)); + uint16_t yComp = (uint16_t) (removeSign(tPoint.a21)); + targetptr = imgdata + (2*(xComp+(yComp*(imgwidth+1)))); + pixVal = pgm_read_word(targetptr); + } else { + pixVal = 12; + } + write_data16(pixVal); + } + } +} + +void perspectiveRasterizeComposite(tri3d t, tri2d tuv, PGM_P imgdata, rectangle imgRegion, float composite){ + _3x3Matrix triangleMat = combine(t.p0, t.p1, t.p2); + _3x3Matrix uvMat = combine2d(tuv.p0, tuv.p1, tuv.p2); + _3x3Matrix invMTM = inverse_3x3(triangleMat); + _3x3Matrix mapping = multiply_3x3(uvMat, invMTM); + plane3d pl = getPlane(t); + + rectangle r = getXYBound3d(t); + uint16_t imgwidth = imgRegion.right-imgRegion.left; + uint16_t imgheight = imgRegion.bottom-imgRegion.top; + rectangleInRegion(&r); + uint16_t width = r.right - r.left; + uint16_t height = r.bottom - r.top; + + tri2d t2d = {{t.p0.a11,t.p0.a21}, + {t.p1.a11,t.p1.a21}, + {t.p2.a11,t.p2.a21}}; + + char* targetptr = imgdata; + uint16_t pixVal; + + if(composite <= 0 || composite > 1.0f) + return; + + for (uint16_t y = 0; y <= r.bottom-r.top; y++) { + uint16_t yVal = y + r.top; + rectangle rReg; + uint16_t topR = y + r.top; + + write_cmd(COLUMN_ADDRESS_SET); + write_data16(r.left); + write_data16(r.right); + write_cmd(PAGE_ADDRESS_SET); + write_data16(topR); + write_data16(topR); + write_cmd(MEMORY_READ); + + uint16_t colorValues[width + 1]; + read_data(); //Throw away a byte + for (uint16_t x = 0; x <= r.right-r.left; x++) { + unsigned char r = read_data() >> 2; + unsigned char g = read_data() >> 2; + unsigned char b = read_data() >> 2; + uint16_t value = (((uint16_t)b)>>1) + (((uint16_t)g) << 5) + ((((uint16_t)r)>>1) << 11); + colorValues[x] = value; //It'd be quick to not convert but requires bigger cache, makes this less memory heavy + } + + write_cmd(MEMORY_WRITE); + for (uint16_t x = 0; x <= r.right-r.left; x++) { + uint16_t xVal = x + r.left; + _2x1Matrix point = {xVal, yVal}; + _2x1Matrix tPoint = transpose_2x3(mapping, point); + if(inTriangle(tPoint.a11, tPoint.a21, tuv)){ + uint16_t xComp = (uint16_t) (removeSign(tPoint.a11)); + uint16_t yComp = (uint16_t) (removeSign(tPoint.a21)); + targetptr = imgdata + (2*(xComp+(yComp*(imgwidth+1)))); + pixVal = pgm_read_word(targetptr); + if(pixVal == TRANSPARENTCOLOR){ + pixVal = colorValues[x]; + } else if(composite != 1.0f){ + unsigned char r = ((unsigned char) ((((colorValues[x]>>11) & 31) * (1.0 - composite)) + (((pixVal>>11) & 31) * (composite)))) & 31; + unsigned char g = ((unsigned char) ((((colorValues[x]>>5) & 63) * (1.0 - composite)) + (((pixVal>>5) & 63) * (composite)))) & 63; + unsigned char b = ((unsigned char) (((colorValues[x] & 31) * (1.0 - composite)) + ((pixVal & 31) * (composite)))) & 31; + pixVal = ((uint16_t)b) + (((uint16_t)g) << 5) + ((((uint16_t)r)) << 11); + } + + } else { + pixVal = colorValues[x]; + } + write_data16(pixVal); + } + } +} + +//Credit:Kornel Kisielewicz, https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle + +float triSign (_2x1Matrix p0, _2x1Matrix p1, _2x1Matrix p2){ + return ((p0.a11 - p2.a11) * (p1.a21 - p2.a21)) - ((p1.a11 - p2.a11) * (p0.a21 - p2.a21)); +} + +plane3d getPlane(tri3d t){ + _3x1Matrix Vp2p0 = minus_3x1(t.p2, t.p0); + _3x1Matrix Vp1p0 = minus_3x1(t.p1, t.p0); + _3x1Matrix crossVectors = crossProduct(Vp1p0,Vp2p0); + plane3d p = {crossVectors, t.p0}; + + return p; +} + +float getZ(float x, float y, plane3d p){ + float z = p.anchor.a31 + ((-(p.gr.a11*(x-p.anchor.a11))-(p.gr.a21*(y-p.anchor.a21)))/p.gr.a31); + return z; +} + +unsigned char inTriangle(float x, float y, tri2d t){ + _2x1Matrix px = {x, y}; + float d1 = triSign(px, t.p0, t.p1); + float d2 = triSign(px, t.p1, t.p2); + float d3 = triSign(px, t.p2, t.p0); + + unsigned char hasNegative = (d1 < 0) || (d2 < 0) || (d3 < 0); + unsigned char hasPositive = (d1 > 0) || (d2 > 0) || (d3 > 0); + + return !(hasNegative && hasPositive); +} + + +rect2d transpose2dRect(rect2d t, _2x2Matrix m){ + rect2d tP; + tP.p0 = transpose_2x2(m, t.p0); + tP.p1 = transpose_2x2(m, t.p1); + tP.p2 = transpose_2x2(m, t.p2); + tP.p3 = transpose_2x2(m, t.p3); + + return tP; +} + +tri3d seperate(_3x3Matrix m){ + _3x1Matrix p0 = {m.a11, m.a21, m.a31}; + _3x1Matrix p1 = {m.a12, m.a22, m.a32}; + _3x1Matrix p2 = {m.a13, m.a23, m.a33}; + + tri3d t = {p0, p1, p2}; + return t; +} + +tri3d transpose3dTri(tri3d t, _3x3Matrix m) { + _3x3Matrix m1 = combine(t.p0, t.p1, t.p2); + _3x3Matrix tP = multiply_3x3(m, m1); + return seperate(tP); +} + +_3x3Matrix combine2d(_2x1Matrix m1, _2x1Matrix m2, _2x1Matrix m3){ + _3x3Matrix m = {m1.a11, m2.a11, m3.a11, + m1.a21, m2.a21, m3.a21, + 0, 0, 0}; + return m; +} + +_2x1Matrix transpose_2x3(_3x3Matrix m1, _2x1Matrix m2){ + _2x1Matrix ma = { + (m1.a11 * m2.a11) + (m1.a12 * m2.a21) + m1.a13, + (m1.a21 * m2.a11) + (m1.a22 * m2.a21) + m1.a23, + + }; + return ma; +} \ No newline at end of file