Combining two YV12 image buffers into a single side-by-side image - c++

I have two image buffers in YV12 format that I need to combine into a single side-by-side image.
(1920x1080) + (1920x1080) = (3840*1080)
YV12 is split into 3 seperate planes.
YYYYYYYY VV UU
The pixel format is 12 bits-per-pixel.
I have created a method that memcpys one buffer (1920x1080) into a larger buffer (3840x1080), but it isn't working.
Here is my c++.
BYTE* source = buffer;
BYTE* destination = convertBuffer3D;
// copy over the Y
for (int x = 0; x < height; x++)
{
memcpy(destination, source, width);
destination += width * 2;
source += width;
}
// copy over the V
for (int x = 0; x < (height / 2); x++)
{
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
}
// copy over the U
for (int x = 0; x < (height / 2); x++)
{
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
}
I expected this:
Instead, I get this result:
What am I missing?

What you wanted is this:
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
U1 U1 U2 U2 V1 V1 V2 V2
U1 U1 U2 U2 V1 V1 V2 V2
but your code is actually doing this:
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
Y1 Y1 Y1 Y1 Y2 Y2 Y2 Y2
U1 U1 V1 V1 U2 U2 V2 V2
U1 U1 V1 V1 U2 U2 V2 V2
Here's the corrected code (untested)
BYTE* source = buffer;
BYTE* destination = convertBuffer3D;
// copy over the Y
for (int x = 0; x < height; x++)
{
memcpy(destination, source, width);
destination += width * 2;
source += width;
}
for (int x = 0; x < (height / 2); x++)
{
// copy over the V
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
// copy over the U
memcpy(destination, source, width / 2);
destination += width;
source += width / 2;
}

Related

Triangle rasterization DirectX & Win32 Gdi

I'm currently following Andre Lamothe's book Tricks of the Windows Game Programming Gurus and trying to write my own software renderer with Win32 GDI. However, I got stuck at the triangle rasterization part of the book where the author is using Bresenham's line algorithm. I managed to get the rasterization to work on DirectX, but not on Win32 GDI despite identical rendering code. Both renders a triangle but the DirectX one renders it correctly while the Win32 almost renders it correctly
Link to my code: https://pastebin.com/VwySmQXS
It could be worth mention that the DirectX version is written in c++, while my own is written in C. I wasn't able to get a good screenshot of the two triangles so here is a picture painted in paint of how they both look.
Left is DirectX (how I want it to look), right is Win32 GDI:
Am I missing something here? Both draw_triangle_2d are called with the same arguments.
static void draw_top_tri(struct render_buffer *buffer,
int x1, int y1,
int x2, int y2,
int x3, int y3,
float r, float g, float b, float a)
{
unsigned int color = vec4_to_uint(vec4_mul(Vec4(r, g, b, a), 255.0f));
// this function draws a triangle that has a flat top
float dx_right, // the dx/dy ratio of the right edge of line
dx_left, // the dx/dy ratio of the left edge of line
xs, xe, // the starting and ending points of the edges
height; // the height of the triangle
int temp_x, // used during sorting as temps
temp_y,
right, // used by clipping
left;
// destination address of next scanline
unsigned int *dest_addr = NULL;
// test order of x1 and x2
if(x2 < x1)
{
temp_x = x2;
x2 = x1;
x1 = temp_x;
} // end if swap
// compute delta's
height = (float)(y3 - y1);
dx_left = (x3 - x1) / height;
dx_right = (x3 - x2) / height;
// set starting points
xs = (float)x1;
xe = (float)x2 + (float)0.5;
// perform y clipping
if(y1 < MIN_CLIP_Y)
{
// compute new xs and ys
xs = xs + dx_left * (float)(-y1 + MIN_CLIP_Y);
xe = xe + dx_right * (float)(-y1 + MIN_CLIP_Y);
// reset y1
y1 = MIN_CLIP_Y;
} // end if top is off screen
if(y3 > MAX_CLIP_X)
y3 = MAX_CLIP_X;
// compute starting address in video memory
dest_addr = (unsigned int *)buffer->memory + y1 * buffer->width;
// test if x clipping is needed
if(x1 >= MIN_CLIP_X && x1 <= MAX_CLIP_X &&
x2 >= MIN_CLIP_X && x2 <= MAX_CLIP_X &&
x3 >= MIN_CLIP_X && x3 <= MAX_CLIP_X)
{
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
memset((unsigned int *)dest_addr + (unsigned int)xs,
color, (unsigned int)(xe - xs + 1) * 4);
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
} // end for
} // end if no x clipping needed
else
{
// clip x axis with slower version
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
// do x clip
left = (int)xs;
right = (int)xe;
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
// clip line
if(left < MIN_CLIP_X)
{
left = MIN_CLIP_X;
if(right < MIN_CLIP_X)
continue;
}
if(right > MAX_CLIP_X)
{
right = MAX_CLIP_X;
if(left > MAX_CLIP_X)
continue;
}
memset((unsigned int *)dest_addr + (unsigned int)left,
color, (unsigned int)(right - left + 1) * 4);
} // end for
} // end else x clipping needed
} // end Draw_Top_Tri
static void
draw_bottom_tri(struct render_buffer *buffer,
int x1, int y1,
int x2, int y2,
int x3, int y3,
float r, float g, float b, float a)
{
unsigned int color = vec4_to_uint(vec4_mul(Vec4(r, g, b, a), 255.0f));
// this function draws a triangle that has a flat bottom
float dx_right, // the dx/dy ratio of the right edge of line
dx_left, // the dx/dy ratio of the left edge of line
xs, xe, // the starting and ending points of the edges
height; // the height of the triangle
int temp_x, // used during sorting as temps
temp_y,
right, // used by clipping
left;
// destination address of next scanline
unsigned int *dest_addr;
// test order of x1 and x2
if(x3 < x2)
{
temp_x = x2;
x2 = x3;
x3 = temp_x;
} // end if swap
// compute delta's
height = (float)(y3 - y1);
dx_left = (x2 - x1) / height;
dx_right = (x3 - x1) / height;
// set starting points
xs = (float)x1;
xe = (float)x1; // +(float)0.5;
// perform y clipping
if(y1 < MIN_CLIP_Y)
{
// compute new xs and ys
xs = xs + dx_left * (float)(-y1 + MIN_CLIP_Y);
xe = xe + dx_right * (float)(-y1 + MIN_CLIP_Y);
// reset y1
y1 = MIN_CLIP_Y;
} // end if top is off screen
if(y3 > MAX_CLIP_X)
y3 = MAX_CLIP_X;
// compute starting address in video memory
dest_addr = (unsigned int *)buffer->memory + y1 * buffer->width;
// test if x clipping is needed
if(x1 >= MIN_CLIP_X && x1 <= MAX_CLIP_X &&
x2 >= MIN_CLIP_X && x2 <= MAX_CLIP_X &&
x3 >= MIN_CLIP_X && x3 <= MAX_CLIP_X)
{
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
memset((unsigned int *)dest_addr + (unsigned int)xs,
color, (unsigned int)(xe - xs + 1) * 4);
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
} // end for
} // end if no x clipping needed
else
{
// clip x axis with slower version
// draw the triangle
for(temp_y = y1; temp_y <= y3; temp_y++, dest_addr += buffer->width)
{
// do x clip
left = (int)xs;
right = (int)xe;
// adjust starting point and ending point
xs += dx_left;
xe += dx_right;
// clip line
if(left < MIN_CLIP_X)
{
left = MIN_CLIP_X;
if(right < MIN_CLIP_X)
continue;
}
if(right > MAX_CLIP_X)
{
right = MAX_CLIP_X;
if(left > MAX_CLIP_X)
continue;
}
memset((unsigned int *)dest_addr + (unsigned int)left,
color, (unsigned int)(right - left + 1) * 4);
} // end for
} // end else x clipping needed
} // end Draw_Bottom_Tri}
ENGINE_CORE_EXPORT void
draw_triangle_2d(struct render_buffer *buffer,
int x1, int y1,
int x2, int y2,
int x3, int y3,
float r, float g, float b, float a)
{
// this function draws a triangle on the destination buffer
// it decomposes all triangles into a pair of flat top, flat bottom
int temp_x, // used for sorting
temp_y,
new_x;
// test for h lines and v lines
if((x1 == x2 && x2 == x3) || (y1 == y2 && y2 == y3))
return;
// sort p1,p2,p3 in ascending y order
if(y2 < y1)
{
temp_x = x2;
temp_y = y2;
x2 = x1;
y2 = y1;
x1 = temp_x;
y1 = temp_y;
} // end if
// now we know that p1 and p2 are in order
if(y3 < y1)
{
temp_x = x3;
temp_y = y3;
x3 = x1;
y3 = y1;
x1 = temp_x;
y1 = temp_y;
} // end if
// finally test y3 against y2
if(y3 < y2)
{
temp_x = x3;
temp_y = y3;
x3 = x2;
y3 = y2;
x2 = temp_x;
y2 = temp_y;
} // end if
// do trivial rejection tests for clipping
if(y3 < MIN_CLIP_Y || y1 > MAX_CLIP_X ||
(x1 < MIN_CLIP_X && x2 < MIN_CLIP_X && x3 < MIN_CLIP_X) ||
(x1 > MAX_CLIP_X && x2 > MAX_CLIP_X && x3 > MAX_CLIP_X))
return;
// test if top of triangle is flat
if(y1 == y2)
{
draw_top_tri(buffer, x1, y1, x2, y2, x3, y3, r, g, b, a);
} // end if
else
if(y2 == y3)
{
draw_bottom_tri(buffer, x1, y1, x2, y2, x3, y3, r, g, b, a);
} // end if bottom is flat
else
{
// general triangle that's needs to be broken up along long edge
new_x = x1 + (int)(0.5 + (float)(y2 - y1) * (float)(x3 - x1) / (float)(y3 - y1));
// draw each sub-triangle
draw_bottom_tri(buffer, x1, y1, new_x, y2, x2, y2, r, g, b, a);
draw_top_tri(buffer, x2, y2, new_x, y2, x3, y3, r, g, b, a);
} // end else
} // end Draw_Triangle_2D

Operations of the elements of arrays in a function' c++

Can I operate the elements of an array in a function(in the parameter)?
float f(i, u, v)
{
if (i == 1) {
return (u - v); //example of the returned value
}
if (i == 2) {
return (u + v);
}
}
int main()
{
int i;
float x[3],y1,y2,h;
x[1]=1;//value of the first element of x[m]
x[2]=1;
h=0.01;
for (i = 1; i <= 2; i++) {
y1=h * f(i, x[1], x[2]);
y2=h * f(i, x[1] + y1/2, x[2]+y1/2);
y3=h* f(i,x[1] + y2/2, x[2]+y2/2);
y4=h * f(i,x[1] + y3, x[2]+y3);
x[1]=x[1] + (y1+ 2 * y2 + 2 * y3+2 * y4)/ 6;
x[2]=x[2] + (y1+ 2 * y2 + 2 * y3+2 * y4)/ 6;
cout<<x[1]<<endl;
}
}
with:
x[1] and x[2] are the elements of the array x[m]
How can I operate elements of different arrays in parameter?
I would recommend you to try to compile your code, the compiler will give you some important hints as of what is wrong. Here is the code compiled online.
To make it compile i changed it to this:
#include <iostream>
using namespace std;
float f(int i, float u, float v) {
if (i == 1) {
return (u - v); // example of the returned value
}
// if (i == 2) { // This if-statement is not needed
return (u + v);
// }
}
int main() {
int i;
float x[3] = {0, 1, 1}; // x[0] is unused...?
float y1 = 0;
float y2 = 0;
float y3 = 0;
float y4 = 0;
const float h = 0.01;
for (int i = 1; i <= 2; i++) {
y1 = h * f(i, x[1], x[2]);
y2 = h * f(i, x[1] + y1 / 2, x[2] + y1 / 2);
y3 = h * f(i, x[1] + y2 / 2, x[2] + y2 / 2);
y4 = h * f(i, x[1] + y3, x[2] + y3);
x[1] = x[1] + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
x[2] = x[2] + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
cout << x[1] << endl;
}
}
Note the changes
You need to specify the types for the variables in the function f(...)
You need to define all variables before using them (a good rule is to specify everything right before you use it, and add const if not changed.
Remember to zero initialize variables that you are going to add to (y1, y2... etc)
Also I would recommend you to use x1 instead of x1, since you are mixing styles between x and y, and you are not using the zeroeth element. Like this
int main() {
int i;
float x1 = 1;
float x2 = 2;
float y1 = 0;
float y2 = 0;
float y3 = 0;
float y4 = 0;
const float h = 0.01;
for (int i = 1; i <= 2; i++) {
y1 = h * f(i, x1, x2);
y2 = h * f(i, x1 + y1 / 2, x2 + y1 / 2);
y3 = h * f(i, x1 + y2 / 2, x2 + y2 / 2);
y4 = h * f(i, x1 + y3, x2 + y3);
x1 = x1 + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
x2 = x2 + (y1 + 2 * y2 + 2 * y3 + 2 * y4) / 6;
cout << x1 << endl;
}
}

Drawing a flat bottom triangle, results in flat top triangle

I'm trying to draw a flat bottom triangle, but its drawn as flat top triangle.
I would like to know what I'm doing wrong, in terms of math
here is my code
void Rasterizer::DrawBottomTriangle(int x0, int y0, int x1, int y1, int x2, int y2, Color color)
{
int temp_x;
// test order of x1 and x2
if (x2 < x1)
{
temp_x = x1;
x1 = x2;
x2 = temp_x;
} //
float dxy_left = (float)(x2 - x0) / (y2 - y0);
float dxy_right = (float)(x1 - x0) / (y1 - y0);
// set starting and ending points for edge trace
float xs = x0;
float xe = x0;
// draw each scanline
for (int y = y0; y >= y1; y--)
{
// draw a line from xs to xe at y in color c
DrawLine(color, (int)xs, y, color, (int)xe, (int)y);
// move down one scanline
xs += dxy_left;
xe += dxy_right;
} // end for y
}

Calculating a exact spline with 3 given Points in 2D. C++

I have a std::vector with 3 points (2D) with values x >= 0 and x <= 512.
With these 3 points I have to calculate a draw that passes all of these 3 points.
Here
you see the 3 Points and the corresponding circle. I need a function to interpolate the points based on a variable which defines the accuracy (eg the number of points inbetween).
If its not clear: I work in C++.
To solve your issue you need to calculate center of triangle's circumscribed circle and it radius. Then find min X and max X from triangle coordinates then calculate delta between maxX - minX and divide delta to numbers of input points. Then in loop you iterates from minX to maxX and calculate coordinates by using circle formula R^2 = (x - centerX)^2 + (y - centerY)^2.
Below a small example
#include <iostream>
#include <vector>
#include <math.h>
template <typename T>
class CPoint2D
{
public:
CPoint2D(T _x, T _y)
: x(_x)
, y(_y)
{}
~CPoint2D()
{}
const T& X() const { return x; }
const T& Y() const { return y; }
private:
T x;
T y;
};
typedef CPoint2D<float> CPoint2Df;
bool GetCenterCircumscribedCircle(float x0, float y0,
float x1, float y1,
float x2, float y2,
float& centerX, float& centerY, float& radius)
{
if ((x0 == x1 && x1 == x2) ||
(y0 == y1 && y1 == y2))
{
return false;
}
float D = 2.0f * (y0 * x2 + y1 * x0 - y1 * x2 - y0 * x1 - y2 * x0 + y2 * x1);
centerX = ( y1 * x0 * x0
- y2 * x0 * x0
- y1 * y1 * y0
+ y2 * y2 * y0
+ x1 * x1 * y2
+ y0 * y0 * y1
+ x2 * x2 * y0
- y2 * y2 * y1
- x2 * x2 * y1
- x1 * x1 * y0
+ y1 * y1 * y2
- y0 * y0 * y2) / D;
centerY = ( x0 * x0 * x2
+ y0 * y0 * x2
+ x1 * x1 * x0
- x1 * x1 * x2
+ y1 * y1 * x0
- y1 * y1 * x2
- x0 * x0 * x1
- y0 * y0 * x1
- x2 * x2 * x0
+ x2 * x2 * x1
- y2 * y2 * x0
+ y2 * y2 * x1) / D;
radius = sqrt((x0 - centerX) * (x0 - centerX) + (y0 - centerY) * (y0 - centerY));
return true;
}
void CalculatePointsOnCirle(const std::vector<CPoint2Df>& triVertexes, std::vector<CPoint2Df>& outPoints, float stride)
{
if (triVertexes.size() != 3)
{
return;
}
const CPoint2Df& v1 = triVertexes[0];
const CPoint2Df& v2 = triVertexes[1];
const CPoint2Df& v3 = triVertexes[2];
float minX = std::min(v1.X(), v2.X());
minX = std::min(minX, v3.X());
float maxX = std::max(v1.X(), v2.X());
maxX = std::max(maxX, v3.X());
float deltaX = (maxX - minX) / stride;
float centerX;
float centerY;
float radius;
if (GetCenterCircumscribedCircle(v1.X(), v1.Y(),
v2.X(), v2.Y(),
v3.X(), v3.Y(),
centerX, centerY, radius))
{
for (float x = minX; x < maxX; x += deltaX)
{
float y = sqrt(radius * radius - (x - centerX) * (x - centerX));
outPoints.push_back(CPoint2Df(x, y));
}
}
}
int main(int argc, const char * argv[])
{
std::vector<CPoint2Df> triVertex = {CPoint2Df(0.0f, 0.0f),
CPoint2Df(256.0f, 256.0f),
CPoint2Df(512.0f, 0.0f)};
std::vector<CPoint2Df> outPoints;
CalculatePointsOnCirle(triVertex, outPoints, 4);
for (unsigned int i = 0; i < outPoints.size(); ++i)
{
printf("p[%d]: (%f, %f)\n", i, outPoints[i].X(), outPoints[i].Y());
}
return 0;
}

AntiAliasing routine for downsizing

i'm trying to implement a custom anti-aliasing routine by summing nearest pixels for downsizing an image.
I tried to sum and mean up to 3 pixels-wide but the result is not good, it's as much antialised (edit i mean aliased) as before.
here is the code i used:
h is height
w is width
buf is a buffer containing the values.
out is the output buffer
for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++)
{
int n = 3;
int x1 = x - n;
int x2 = x + n;
if (x1 < 0) x1 = 0;
if (x2 > w -1) x2 = w - 1;
int y1 = y - n;
int y2 = y + n;
if (y1 < 0) y1 = 0;
if (y2 > h - 1) y2 = h - 1;
double sum = 0;
for (int i = x1; i <= x2; i++)
for (int j = y1; j <= y2; j++)
sum += buf[i][j];
sum = sum / double((x2 - x1 +1) * (y2 - y1 +1));
out[x][y] = sum;
}
What quick routine could i use to do a simple basic anti-aliasing?