Regarding GDI Mapping in my Textbook example - c++

This is a snippet of an example in my book. What I don't understand in this code is that the SetWindowOrgEx x value increases positively to the left, why is this? Tehinically this should be like MM_TEXT in which the x value increases going to the right. I notice as well that the x value does increase to the right with SetViewportOrgEx. Why does the x value increase to the right with SetViewportOrgEx but SetWindowOrgEx's x value increases to the left? Also, what's the point of changing both extents? Couldn't you just edit one of the extents?
SetMapMode(hdc, MM_ISOTROPIC);
SetWindowExtEx(hdc, 276, 72, NULL);
SetViewportExtEx(hdc, cxClient, cyClient, NULL);
SetWindowOrgEx(hdc, 138, 36, NULL);
SetViewportOrgEx(hdc, cxClient / 2, cyClient / 2, NULL);

It depends what you're doing, but these functions are used to shift the axis, so the logical point (0, 0) refers to something other than the upper-left corner.
You generally should only be using one functions, SetWindowOrgEx and SetViewportOrgEx, depending on which suits your needs; not both.

Related

2D Coordinate Confusion

Alright, so I have never created a game before, and I am trying to make a 2d tile based game.
So I am really confused about something that should be pretty simple, coordinates.
I have tile coordinates, like
{0,0,0,0,0,1}
{0,0,1,0,0,1}
{0,0,0,0,0,1}
{0,0,1,1,1,1}
{0,0,0,0,0,1}
lets say this is my world and i am trying to render it, well i cant render it, each tile needs a width,
this is where i get confused, so you can do, im not new to coding
twidth = 100, theight = 100;
for(y = each row) {
for(x = each tile in each row) {
draw rect (
X1 = x*twidth,
Y1 = y*theight,
X2 = x*twidth+twidth,
X2 = y*theight+theight
)
}
}
I might be wrong about this, but: now literally everything else needs to multiplied by the twidth/height, it will be even harder if you want different sized tiles, at least its confusing to me, how do other games handle things like this? im not sure if i explained very well what my problem is, any help would be appreciated
im using opengl[legacy] and i think the solution might be a function to setup screenspace differently, so rendering
glVertex2d(0,1) is actually 100px, this would make collisions, and such, much easier
im using opengl[legacy] and i think the solution might be a function to setup screenspace differently, so rendering glVertex2d(0,1) is actually 100px, this would make collisions, and such, much easier
You can achieve that in legacy OpenGL by setting up the projection matrix properly:
glMatrixMode(GL_PROJECTION);
glOrtho(0, 16, 0, 9, -1, 1);
This will set it up so that glVertex2d(0, 0) maps to the bottom left corner and glVertex2d(16, 9) will map to the top right corner, giving you 16x9 tiles in the viewport. To fix the size of the tile in pixels we calculate the fractional number of tiles instead:
glOrtho(0, (double)viewportWidth / twidth, 0, (double)viewportHeight / theight, -1, 1);
After that you can 'scroll' the world by translating it through the GL_MODELVIEW matrix.

How to draw points in random locations but within screen or window boundaries

I am using OpenGL library in my Visual C++ application where I want to draw say, 100 points in random locations and I would like to check if these points random co-ordinates or random locations that generated are within the screen or window boundaries. I tired using a (x,y,z) vertex option and I get the points vertical running along a line. If I try generating only (x,y) and drawing them then I do get a lot more points scattered but definitely not all 100 within the window dimensions.
my code looks something like this:
GLfloat dots_vert[99];
for (int i = 0; i < 99; i++){
if (i % 2 == 0)
dots_vert[i] = 0.0f;
else
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*100.0f - (100.0f / 2);
}
glEnable(GL_POINT_SMOOTH);
glPointSize(3.0f);
glEnableClientState(GL_VERTEX_ARRAY);
GLuint vbo_ID;
glGenBuffers(1, &vbo_ID);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glBufferData(GL_ARRAY_BUFFER, sizeof(dots_vert), dots_vert, GL_DYNAMIC_DRAW);
while (!GetAsyncKeyState(VK_DOWN)){
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glDrawArrays(GL_POINTS, 0, 100);
SwapBuffers(g_pOpenGLWindow->hDC);
Let me guide you through the glaring mistakes I can immediately see in that code.
First of all the obvious first mistake: you claim to be drawing 100 points but your dots_vert array is only 99 elements long. This is repeated in the following loop, where you go from 0 to 98 for a total of 99 times.
So first of all:
GLfloat dots_vert[100];
for (int i = 0; i < 100; ++i)
{
[...]
}
There is another huge mistake in there but we'll keep that for later, let's move on for now.
The second mistake is about the knowledge of the OpenGL API and computer graphics. First of all, your goal is to pass points to the GPU, so you need the glVertexAttribPointer function, that much you figured out. The absolute first thing you wanna do is to look at the glVertexAttribPointer reference documentation, so you have an idea of what you need. You need an index, a size, a type, a normalized flag, a stride and an offset.
Let's look at what the reference documentation says about the size parameter:
size
Specifies the number of components per generic vertex attribute. Must be 1, 2, 3, 4. Additionally, the symbolic constant GL_BGRA is accepted by glVertexAttribPointer. The initial value is 4.
This is immediately obvious to be crucial in determining what kind of data you're trying to pass to the GPU. You set the parameter to 3, which means that you have an x, a y and a z. But the previous code contradicts this. For starters, your dots_vert array is 100 elements long, and you want to draw 100 points, so you have enough for 100/100 = 1 component per point, not 3. But even worse, the inside of the for loop contradicts this even further, so let's go back and check the mistake I mentioned previously.
Mistake number three: your for loop consists of an if {} else {} statement, where you set the current element of the dots_vert array to a value of 0.0f if the index of the loop is even (if (i % 2 == 0)), and a random value between -50.0f and 50.0f otherwise. Assuming 1 component per point, this means that you're only generating the x coordinates, so you're working in a single dimension.
Clearly this is not what you intended to do, also because half of your points will be 0.0f and therefore they'll all overlap. So I assume you were trying to generate a random value for x and y, and set z to 0.0f, which would make much more sense. First of all, you have 3 components per point and therefore you'll need an array with 100*3 = 300 elements. So first of all, let's fix the previous code:
GLfloat dots_vert[300];
for (int i = 0; i < 300; ++i)
{
[...]
}
Much better. Now we need to generate a random x and y valye for each point, and set z to 0.0f since we don't need it. You wanna do all of the components at once in a single loop, so you want your loop to step by 3, not 1, so once again let's fix the previous code:
GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
[...]
}
Now we can generate x, y and z together in a single loop. This is the crucial part where understanding how computer graphics work, specifically in the context of the OpenGL API. OpenGL uses a coordinate system where the origin is in the middle of the screen, the x axis moves horizontally (positive x points to your right), the y axis moves vertically (positive y points up), and the z axis goes straight through the screen (positive z points out of the screen, towards you). Now this is the very important part: x, y and z are clipped to a specific range of values; anything outside of this range is ignored. For all coordinates, the range goes from -1.0f to 1.0f. Anything below of above that is not drawn at all.
So if you want to have 100 points to be inside the screen, ignoring projection which is outside of the scope of this exercise, you want to generate x and y in the -1.0f to 1.0f range, not -50.0f to 50.0f like you're doing there. You can keep z to 0.0f, doesn't really matter in this case. This is why most of your points fall outside of the screen: with that range, statistically speaking, around 98% of your points will fall outside of the clip space and will be ignored.
So ultimately this is what you want:
GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
dots_vert[i+2] = 0.0f; // this is z
}
Finally a reminder: when you do glDrawArrays(GL_POINTS, 0, 100); you're telling the GPU to draw 100 points. Each point is made of however many components you specified in the size parameter of the glVertexAttribPointer function. In this case you wanna draw 100 points, each point is made of 3 components, so the GPU expects an array of 100*3 = 300 floats. numbers. Anything less could result in either a segmentation fault or even worse an undefined behavior (which means anything can happen), so pay close attention to what you're doing and make sure you know exactly what kind of data you're passing to the GPU because you might end up with a nonsense result and you'll be stuck trying to figure out what went wrong. In this case, you have basically no code at all to check so it's easy to fix, but when you'll end up with a decent amount of code (and you will eventually), an error like this could mean hours or even days wasted trying to find the error.
As a bonus, feel free to ignore this one: technically a point is made of 4 components. This component is called w and its use is outside of the scope of this exercise so don't worry about it, just remember that it should always be set to 1.0f, unless you are doing projection.
So technically you could do this too:
GLfloat dots_vert[400];
for (int i = 0; i < 400; i += 4)
{
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
dots_vert[i+2] = 0.0f; // this is z
dots_vert[i+3] = 1.0f; // this is w
}
Then you set the size parameter of glVertexAttribPointer to 4 instead of 3, the result should be exactly the same.

About class CRect & Rect, Width = right - left

It is a problem about C++ and mfc.
For example, left = 3, right = 8. Doesn't it mean there are 6 pixel from left to right? Why the width = right - left? If I know a rect which represents the image rect, when I allocate memory for the image data, which one should I use? Width = right-left, or Width = right-left+1? I am a beginner of image process. It really confuses me. Thank you for your help!
If we are talking about CRect and RECT the documentation is clear.
By convention, the right and bottom edges of the rectangle are normally considered exclusive. In other words, the pixel whose coordinates are ( right, bottom ) lies immediately outside of the rectangle. For example, when RECT is passed to the FillRect function, the rectangle is filled up to, but not including, the right column and bottom row of pixels. This structure is identical to the RECTL structure.
The principles of "inclusive lower bound, exclusive upper bound" is used here to. So the number of elements is always the difference between the boundaries.
Another way to think about this is that the width of the rectangle is a measure of DISTANCE from left to right. When left equals right (e.g.: left = 1 and right = 1), the distance between them is zero (note that the distance can be negative).
When using a RECT to represent pixel coordinates, we often want to know the count of pixels going from left to right. When left equals right (e.g.: left = 1 and right = 1), we know we have only one pixel in the left/right direction. There isn't a pre-made function to compute this count, so you need take the absolute value of the width and add 1.
In C/C++:
int count = abs(myRect.right - myRect.left) + 1;

How to draw curve by InDesign/Illustrator path points?

The following numbers are the path points of a very simple curve from Adobe InDesign:
pathPoint0 = app.selection[0].paths[0].pathPoints[0] // PointType: SMOOTH
pathPoint1 = app.selection[0].paths[0].pathPoints[1] // PointType: PLAIN
pathPoint0.leftDirection : {x=87.32570997045623, y=30.81406367905744}
pathPoint0.anchor : {x=67.69218412206757, y=134.53280706833522}
pathPoint0.rightDirection : {x=48.0586582736789, y=238.25155045761298}
pathPoint1.anchor : {117.05865827421783, 143.2515504576449}
The curve contains 2 path points, an smooth point and a plain point.
InDesign simple curve:
(source: no-ip.org)
I am trying to draw this curve by this code:
MoveToEx(hDC, 67, 134, NULL);
POINT points[] = {{87, 30}, {48, 238}, {117, 143}};
PolyBezierTo(hDC, points, 3);
But I can not draw same curve, my drawn curve is:
(source: no-ip.org)
Where is my mistake? Is any conversion need?
Thanks.
Hmm...
MoveToEx(hDC, 67, 134, NULL);
POINT points[] = {{87, 30}, {48, 238}, {117, 143}};
Your first point is 67,134 your second is 87,30 and your third 48,238.
With Y values of 134 then 30 then 238, I'd expect about what you seem to be getting -- a line that goes one direction, then sharply back in about the opposite direction.
The first point you're getting from InDesign is a "direction" point -- but for PolyBezier, the first and last points are the anchors. I'm not absolutely certain, but I think what you want is to rearrange the points so your anchors come first and last, and InDesign's "direction" points are used as the two control points in between:
POINT points[] = {{87, 30}, {67, 134}, {48,238}, {117, 143}};
// anchor, control, control, anchor
PolyBezier(hDC, points, 4);
Unless you're using MoveTo/LineTo (and such) otherwise, I'd just PolyBezier instead of PolyBezierTo -- keeps all the data in one place.

can't understand following c++ code line

I'm new with C++, and try to figuring out what this line of code means:
cur_rect = cv::Rect(cur_rect) & cv::Rect(0, 0, mat->cols, mat->rows); // here
if( cv::Rect(cur_rect) == cv::Rect() ) //here
{
.......
}
The Rect & Rect part intersects two rectangles and gives a non-empty rectangle back when the two inputs overlap.
So you can compare the result to Rect() to see whether there was an intersection. Your code crops cur_rect to (0, 0, mat->cols, mat->rows) and then checks whether it is empty or not.
Sources:
http://opencv.willowgarage.com/documentation/cpp/core_basic_structures.html?highlight=rect
How can one easily detect whether 2 ROIs intersects in OpenCv?
Edit
An alternative implementation, a bit cleaner:
// crop cur_rect to rectangle with matrix 'mat' size:
cur_rect &= cv::Rect(0, 0, mat->cols, mat->rows);
if (cur_rect.area() == 0) {
// result is empty
...
}
I am assuming that cv::Rect(...) methods (or family of them) returns a rectangle object. The line that you do not understand, I assume is an overloaded operator (==) that compares rectangles.
But I am making a lot of assumptions here as I do not have the code for cv class.
As to the & overloaded operator - one assumes that this is doing an intersection or union. Once again without the code it is hard to say.