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.
Related
When drawing a quad, it vanishes when rotation brings in a position perpendicular to the screen. Ideally what I'd like to see is (b) but I get nothing
Is there something wrong with my code ? (warning old openGL code following)
void draw_rect(double vector[4][3], int rgb[3], double transp)
{
GLint is_depth, is_blend, blend_src, blend_dst;
glGetIntegerv(GL_DEPTH_WRITEMASK, &is_depth);
glGetIntegerv(GL_BLEND, &is_blend);
glGetIntegerv(GL_BLEND_SRC, &blend_src);
glGetIntegerv(GL_BLEND_DST, &blend_dst);
glEnable(GL_BLEND);
glDepthMask(0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// code to set the color ...
glBegin(GL_POLYGON);
glVertex3v(&vector[0][0]);
glVertex3v(&vector[1][0]);
glVertex3v(&vector[2][0]);
glVertex3v(&vector[3][0]);
glEnd();
if (!is_blend){ glDisable(GL_BLEND); }
glDepthMask(is_depth);
glBlendFunc(blend_src, blend_dst);
}
A quad (assuming it is defined by coplanar faces, as in this case) is by definition infinitely thin. It is correct behavior for it to be invisible when perpendicular to the camera.
The "correct" solution is to make a box rather than a single quad.
See Drawing cube 3D using Opengl for an example using a cube. You'll need to tweak the vertex positions to make the cube smaller along one dimension (probably Z), but it'll give you the effect that you're looking for.
Also, stop using the fixed function stuff (glVertex, etc.). It's been deprecated for years. Shaders aren't that difficult, and examples are easy to find via your favorite search engine.
try making it a line of some definite width when the quad is perpendicular to the screen
just wondering how someone would go about dragging 4 different
objects in openGL. I have very simple code to draw these objects:
glPushMatrix();
glTranslatef(mouse_x, mouse_y, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x2, mouse_y2, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x3, mouse_y3, 0);
glutSolidIcosahedron();
glPopMatrix();
glPushMatrix();
glTranslatef(mouse_x4, mouse_y4, 0);
glutSolidIcosahedron();
glPopMatrix();
I understand how to move an object, but I want to learn how to drag and drop any one of these objects.
I've been researching about the Name Stack and Selection Mode, but it just confused the hell out of me.
And I also know about having to have some sort of glutMouseFunc.
It's just the selection of each shape I'm puzzled on.
First thing that you need to do is capturing the position of mouse on the screen when the button is clicked. There are plenty of ways to do it but I believe it's outside of the scope of this question. When you have screen X,Y coords you must detect if any object is selected and which one it is. There are two possible approaches. You can either keep track of a bounding rectangle positions of each object (in screen space) and the test if the cursor is inside any of those rectangles will be quite simple. Or you can cast a ray from eye through cursor position in world space and check intersection of this ray with each object.
The second approach is more versatile for 3D graphics but you seem to be using only X and Y coords so you don't need to worry about Z order of objects.
In case of the first solution the main problem is: how to know how big is your object on the screen. glutSolidIcosahedron() renders an object of radius 1. To calculate it's screen radius you can either use some matrix math or in that case a simple trigonometry. You will need to know the distance from camera to the drawing plane (I believe you're using some glTranslatef(0,0,X) before you render. X is your distance) You also need to know the view angle of the camera. You set it in projection matrix. Now take a piece of paper, draw a cone of angle alpha, intersecting a plane at distance X and knowing that an object has radius 1 you can easily calculate how large area of the screen it occupies. (I'll leave this calculation for you)
Now if you know the radius on screen, simply test the distance from your click position to each object. if the distance is below radius it's selected. If more than one object passes this test just select first one of them.
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.
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);
I have a sprite, a square, just for orthogonal projection. Now I want to project it in a very basic, simple isometric way. (I know this might not be pretty, but I just want to figure this out)
Given my square, I rotate it 45 degrees. Now if I understand correctly, I should still divide my height by 2. This has been impossible for me in SFML. There is a scale function but if I scale with a factor 0.5 in the y-axis direction, my cube just gets stretched, instead of a diamond shape. It looks as though SFML transforms the sprite according to it's own relative axes (that were rotated before..).
Since you cannot access the height of a sprite, I was wondering if this was even possible?
Can I convert a square sprite to a diamond shape in SFML?
Using a sf::RenderTexture is an option (see other answer). Another option is to fiddle with the sf::View. Double the view's height, and adjust coordinates. It would go something like this:
my_sprite.setRotation(45.f);
//adjust the position for new screen coordinates (once)
my_sprite.setPosition(my_sprite.getPosition().x, my_sprite.getPosition().y * 2);
//...
//when drawing:
sf::View v = my_render_window.getDefaultView();
v.setSize(v.getSize().x, v.getSize().y * 2);
v.setCenter(v.getSize() *.5f);
my_render_window.setView(v);
my_render_window.draw(my_sprite);
my_render_window.setView(my_render_window.getDefaultView());
Rotate your sprite as you are doing now. Render it to an sf::RenderTexture. Use the member function getTexture, and make a new sprite from it, or reuse the old sprite. Scale the sprite along the y-axis. Draw it to the render window.
Some math on your part may be required in order to set the RenderTexture to the right size and to draw the original sprite in the correct location on it.
original_sprite.setRotation(45);
sf::RenderTexture rt;
rt.create(FigureOutWidth(),FigureOutHeight());
original_sprite.setPosition(MoreMathHere());
rt.draw(original_sprite);
sf::Sprite new_sprite(rt.getTexture());
new_sprite.setScale(1.0,0.5);
It should go without saying, but do this once in initialization, not every frame.