C++ SFML Drawing scrollable content within a defined rectangle - c++

I'm having trouble drawing scrollable content within a defined rectangle. What I would like to achieve is the ability to freely scroll the contents within a rectangle, with anything that is not within or partially in being cropped. At present I scroll by the number of items available to make sure nothings being drawn outside of the rectangle.
Looking at what's available in SFML it seems I should be able to achieve this using sf::View but my attempts are not working.
sf::View panelView;
panelView.reset(sf::FloatRect(220,85,815,575));
panelView.setViewport(sf::FloatRect(0, 0, 1.0f, 1.0f));
I'm then setting the viewpoint to this, drawing my items, then going back to the default view. It always seems to draw to the entire screen though instead of the desired rectangle i've set in the Reset method?
My understanding is that this should create the viewport at 220 on the x axis, 85 on the y axis and be 815 wide and 575 high, but it's drawing outside of this boundaries.
Any ideas?

Sorted out the issue looking into it a little bit further - seems I just need to set my position as a factor between 0.0f and 1.0f, where position in my sample code below is where I want the viewport to be positioned:
sf::FloatRect panelRect(position.left / SCREENWIDTH,
(position.top) / SCREENHEIGHT,
(position.width) / SCREENWIDTH,
(position.height) / SCREENHEIGHT);
panelView.reset(sf::FloatRect(position.left,position.top,position.width,position.height));
panelView.setViewport(panelRect);

Related

confusion in viewport transformation and geometry being stretched or squeezed

i have opengles setup using emscripten to draw geomatries on a html canvas.
currently i am facing two problems,
i am not sure the viewport transformation is working properly or not,
the geometry gets squeezed or stretched on canvas resize.
the canvas is generated using this line:
<canvas id="webgl_main_canvas" style={{width:"100%",height:"100%"}} />
now with the width and height of this canvas, i setup glViewport configuration and projection matrix using:
glViewport(0, 0, (GLfloat)canvas_width, (GLfloat)canvas_height);
projection = glm::perspective(glm::radians(45.0f), (float)(width/height), 0.1f, 1000.0f);
when i try to render something, the result of is a black screen black screen, here the geometry is actualty there but, it is drawn somewhere far top right hence outside of the screen.
but if i set glViewport configuration using width=350 and height=150, the geometry is visible like this. the special thing about this dimension is that it is the default dimension of canvas as if it is created just using this:
<canvas id="webgl_main_canvas"/>
the inline style style={{width:"100%",height:"100%"}} only tells the canvas to occupy 100% area of its parent div.
so to summarize, creating the canvas like this <canvas id="webgl_main_canvas" style={{width:"100%",height:"100%"}} />:
if i render(after setting glViewport and projection matrix) using the actual width and height i get an black screen.
but if i use dimention(350,150) the geomatry is visible.
As mentioned here viewport tranformation, i am guessing in the first case, first the whole geomatry is stretched due to style={{width:"100%",height:"100%"}}and then vertices are tranfomred using the current width and height.
what could be the issue here? i want to use the actual width and height properly here.
also, for all this i am creating the view matrix using like this:
glm::vec3 cameraPos = glm::vec3(0,0,1);
glm::vec3 camerafront = glm::vec3(0, 0, -1);
glm::vec3 cameraUp = glm::vec3(0, 1, 0);
view = glm::lookAt(cameraPos, cameraPos + camerafront, cameraUp);
Found the issue, so basically an HTML canvas has 2 sizes, one is drawingbuffer size, and the other is the size that is being displayed through CSS, [as mentioned here][4], what i was doing wrong was not setting my drawingbuffer siz, hence it was always picking the default size which was 300x150, and while setting the glViewport the width and height that i was using was wrt the CSS style, which was creating the issue.
solution is to define the the canvas like this:
<canvas id="webgl_main_canvas" width="1200" height="800" style={{width:"100%",height:"100%"}} />
here width="1200" height="800" is acuatlly setting the drawingbuffer size of the HTML canvas.
and whenever you want to resize, just change these values repectively.

Coordinates Within Draw Method of a Subclass of CCSprite

I am using Cocos2d v2.1. I subclassed CCSprite and have overwritten the draw method. I am calling [super draw] so everything with regard to the sprite itself is drawing correctly.
All I want to do at this point is use the draw method to place a red dot directly at the sprites position. In short, this red dot should appear at the center point of the sprite. I am using the ccDrawSolidCircle function.
Well, the dot is being drawn, but it is not aligned with the sprite. As I move the sprite around the screen the dot moves with it. The further away I am from position 0,0 the further the dot moves away from the sprite. When I move the sprite to position 0,0 the dot is correctly placed.
Since it was moving this way I assumed this had to do with points versus pixels, thus I multiplied the position of the dot by .5. This brought the dot closer, but the behavior continued. I then tried using the convertToNodeSpace and convertToWorldSpace functions, but none of this worked. But maybe there is some combination of these methods that would work. Who knows.
I have never had to worry about the coordinates when overriding the draw method of a CCNode subclassed object, but for CCSprite it does not work the same. This is probably because the draw method of CCNode is empty.
There is probably a simple solution to this, and probably related to openGL coordinates versus cocos2d coordinates, but I am unable to determine this nor can I find something in the various forums. Any help would be appreciated.
Thanks!
EDIT 1: Well, I found something that works, but whether this is the best solution I do not know. I computed a new center position with the following line of code:
adjustedPosition = ccp(self.quad.bl.texCoords.u + self.contentSize.width / 2, self.quad.bl.texCoords.v + self.contentSize.height / 2);
So far so good. But if anyone can shed some further light on this, please do so.
Thanks again!
EDIT 2: My draw method code before EDIT 1 was as follows:
- (void) draw {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1);
ccDrawColor4B(255, 0, 0, 255);
ccDrawSolidCircle(ccp(self.position.x, self.position.y), 4, 10);
}
After the edit it is now this:
- (void) draw {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1);
ccDrawColor4B(255, 0, 0, 255);
adjustedPosition = ccp(self.quad.bl.texCoords.u + self.contentSize.width / 2, self.quad.bl.texCoords.v + self.contentSize.height / 2);
ccDrawSolidCircle(ccp(adjustedPosition.x, adjustedPosition.y), 4, 10);
}
The "adjustedPosition" code has thus far been working correctly.

Clicking on a Quad and getting screen coords in opengl

Say I make a quad like so:
float botBaseY = -0.5;
glBegin(GL_QUADS); // Box
glVertex2f(-.05, botBaseY + -.05);
glVertex2f(-.05, botBaseY + .05);
glVertex2f(.05, botBaseY + .05);
glVertex2f(.05, botBaseY + -.05);
glEnd();
OK, well now say I want to determine if the user clicked inside of that quad.
Well when you click, you receive screen coordinates, so if your main window is
600x600 pixels, then your click will yield an x and y value less than 600.
But I'm comparing a click at say (375,400) to a quad that was created using
values from -1.0 to 1.0 to define the 4 vertices.
How can I determine if the user clicked inside of the quad?
I currently see 2 ways to do this.
if your 'interface' is completely 2D and directly mapped into screen - you could just use screen coordinates for drawing. Just set correct orthographic matrix and your click coordinates will be the same as 2D elements coordinates - simple range comparison (x < click_x < x+width). See gluOrtho2D, glOrtho manuals (please note that glOrtho and other matrix functions are not available in newest GL profiles).
if first variant isn't fitting your situation - you need to map 2D coordinates to view space and use resulting point as ray direction. Then trace this ray's intersection with element's plane you want to click. Take a look at http://www.toymaker.info/Games/html/picking.html - doesn't matter that it's for d3d, math is always the same). Then, when you'll take resulting click point on a plane you've interested in - it's again just range comparison (although it will be a little trickier if your plane is not parallel to screen - but i don't think it still the same question).
I never ended up getting a useful answer on here, but I did end up figuring it out the next day. My box was being drawn using coordinates that were from -1 to 1. But my click had large screen coordinates such as 200,300. I needed to know how to convert the -1 to 1 into screen coordinates, or how to just draw it compatible coordinates.
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0, 400, 0, 400);
glBegin(GL_QUADS); // Box
glVertex2f(xOffset + topBaseX + -15, topBaseY + -15);// bottom left vert
glVertex2f(xOffset + topBaseX + -15, topBaseY + 15); // top left vert
glVertex2f(xOffset + topBaseX + 15, topBaseY + 15);// top right vert
glVertex2f(xOffset + topBaseX + 15, topBaseY + -15);// bottom right vert
glEnd();
glLoadIdentity();
That was all I had to do to draw my box at something like 200,300 and then I could simply check the boundaries of my box on each click.
Easiest and most accurate (but not necessarily most efficient) way:
Render the scene again (into an off-screen buffer) with the target object white and all else black. If the pixel under the cursor is white, the target was clicked. If you want to be able to click through some transparent materials, just skip rendering those objects.
For efficiency, you can do this with blending turned off and a unique color (perhaps an index) for each object. And use new OpenGL capabilities to fill the picker color plane during normal rendering instead of taking an additional pass.

How can I extend my viewport in openGL to keep printed text clipped properly?

I am using this code to draw a text in openGL with GLUT:
Code (init part) which sets my origin (0,0) into top-left corner and maintains proper screen-resolution based coordination system :
glViewport(0, 0, x, y);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, x, y, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
Code (printing part) :
void drawtext(GLfloat x, GLfloat y, const char* string )
{
glRasterPos2f(x,y);
while ( *string != '\0' )
glutBitmapCharacter(p_glutfont,static_cast<int>(*string++));
}
And everything would be perfect if not only the fact that when X and Y starts at negative coordinations (due to the fact that objects with text printed as a tag are partially outside of the view, then the whole text is not being drawn. lets imagine that I have a object with text tag on top of it and it enters the view from left top corner at x = -40, y = 40 :
X axis window
axis Y ----------------------------
| y=40 |
x=-40__|_________ |
|Text to print| |
|_____________| |
| |
| |
|____________________________|
The text is not being printed until is drawn from exactly X => 0 coordination. Also this problem doesn't exist when text has to be clipped on RIGHT side - then it is printed properly - this is where I I realized that it has to do with initial position of the text.
My question is - how can I EXTEND properly my viewport / screen mapping to :
1) preserve screen coordinations from top-left corner (0,0) to bottom-right (height,width) 2) with internally extended those values just during the printing the text - so the text would get clipped instead of disappearing ?
Although I did my research, I couldn't for 2 days now come to any solution. I tried to play with glViewport and glOrtho but none of changes and approaches I tried (like for example setting glViewport to -x,-y,x*2,y*2) would do the trick - those always mess with my screen coordination system which is essential to keep at window-resolution based.
PS: I did further research and I came across this article http://www.opengl.org/archives/resources/faq/technical/clipping.htm.
10.070 How do I draw glBitmap() or glDrawPixels() primitives that have an initial glRasterPos() outside the window's left or bottom edge?
When the raster position is set outside the window, it's often outside
the view volume and subsequently marked as invalid. Rendering the
glBitmap and glDrawPixels primitives won't occur with an invalid
raster position. Because glBitmap/glDrawPixels produce pixels up and
to the right of the raster position, it appears impossible to render
this type of primitive clipped by the left and/or bottom edges of the
window.
However, here's an often-used trick: Set the raster position to a valid value inside the view volume. Then make the following call:
glBitmap (0, 0, 0, 0, xMove, yMove, NULL);
This tells OpenGL to render a no-op bitmap, but move the current
raster position by (xMove,yMove). Your application will supply
(xMove,yMove) values that place the raster position outside the view
volume. Follow this call with the glBitmap() or glDrawPixels() to do
the rendering you desire.
Sadly - I can't put this advice in work - and once I use it - the text is completely missing.
this is where I I realized that it has to do with initial position of the text.
Almost. glRasterPos is a raster drawing operation command and whatever position you put into it goes through the transformation pipeline. If the point falls outside the clip volume (not the viewport!) it gets discarded and all further raster drawing operations are disabled until a new glRasterPos specified that is not clipped.
The easy and recommended solution would be not to use raster drawing operations at all, because they're slow, poorly supported and have been removed from later OpenGL alltogether. glutBitmapCharacter is using raster drawing ops.
Use texture mapped fonts or stroked characters instead. Google finds uncountable amounts of information on these.

OpenGL coordinates question

I have a simple OpenGL drawing. When the user changes the window's size, I want the drawing to maintain it's aspect ration. I accomplished that by setting the glViewport to the maximum rectangle with the appropriate aspect ration whenever the reshape method is called.
My problem is that I want to draw a square that will always remain in the top right corner of the window, no matter what the size or shape of the window is. Right now, that square moves around the screen whenever the window is reshaped.
Can anyone please explain how to do this?
Thank you,
You need to move/size the square when the screen is re-sized. You can fix a square to the top left by using device coordinates but it won't necessarily be square of the aspect ratio changes. Therefore you need to resize the square to keep it square.
One way of doing this would be to create a new ortho matrix that maps to pixel coordinates (left = 0, bottom = 0, right = window-width, top = window-height) and set the gl-viewport to cover the entire window whenever the window changes. That way, you can draw a square by specifying pixel coordinates, if you make sure you have an identity model-view matrix set up.
It's not the only way, though. No matter what non-singular transformation you have, you should be able to come up with a way of hitting the correct pixels as long as the gl-viewport covers those, it's just easier this way.
If I understand correctly, you wish to draw a square at the top right corner of the window, regardless of where your scene viewport is positioned.
The easiest way to do this is to, after having rendered your normal scene with desired aspect, change the gl viewport to the square you want to draw in the top corner. Then draw a "full-screen" quad to fill the square, with full-screen in-fact becoming full-viewport in this case.
Untested semi-pseudo code would go something like this:
// Draw normal scene
glViewport(x, y, w, h);
drawScene();
// Draw top-right red square
glViewport( windowWidth - squareWidth, windowHeight - squareHeight,
squareWidth, squareHeight );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glColor3f(1.f, 0.f, 0.f);
glRectf(-1.f, -1.f, 1.f, 1.f);
Making sure that the winding of the glRectf matches your current gl cull face configuration. Alternatively, just temporarily disable culling by glDisable(GL_CULL_FACE) / glEnable(GL_CULL_FACE).
To draw a square in the top-right corner of the window, you need the viewport to cover this area. Having a viewport smaller than the window won't allow drawing in the corner.
You want your viewport to cover all the window (as done usually), and your square coordinates should be mapped to something like:
X0 = 1-2*s/width
X1 = 1
Y0 = 1-2*s/height
Y1 = 1
where s is the side of the square (pix), and width, height the dimensions of the window (pix).