SDL - Move cursor with rect x and y smaller than zero - cursor

I implemented a custom cursor on my SDL game. When moving it across the screen I can go as far as I want to the right and to the bottom. But the cursor will not go beyond the ledt or the top wall. I'm using SDL_GetMouseState and passing the current x and y values to it.
How do I manage to allow a surface to move to the position (-5, 0)?
Here's some code:
typedef struct {
SDL_Surface *image;
SDL_Rect frame;
} Cursor;
void moveCursor(Cursor *cursor) {
Sint16 *x = &cursor->frame.x;
Sint16 *y = &cursor->frame.y;
Uint16 cursorWidth = cursor->frame.w;
Uint16 cursorHeight = cursor->frame.h;
SDL_GetMouseState((int *)x, (int *)y);
cursor->frame.w = cursorWidth;
cursor->frame.h = cursorHeight;
SDL_Rect temporaryFrame = cursor->frame;
SDL_BlitSurface(cursor->image, NULL, bufferSurface.surface, &temporaryFrame);
}

SDL doesn't detect mouse movements outside its window, so you cannot have negative mouse coordinates.
To simulate a mouse that can move offscreen, always keep the mouse centered and store it's relative motion. The relative motion is translated to your virtual mouse that can now move anywhere and is represented by a sprite.

Related

Rotating sprite with a center of rotation in SDL2

I want to rotate a sprite in C and SDL2, with a set center of rotation, and without scaling or anti-aliasing.
My game resolution is 320x240, and the display is scaled up when I set the game to full screen, because I'm using SDL_RenderSetLogicalSize(renderer, 320, 240).
Using SDL2's SDL_RenderCopyEx() (or SDL_RenderCopyExF()) to rotate a SDL_Texture.
As shown in this example ( https://imgur.com/UGNDfEY ) when the window is set to full screen, the texture is scaled up and at much higher resolution. Is would like the final 320x240 rendering to be scaled up, not the individual textures.
Using SDL_gfx's rotozoomSurface() was a possible alternative.
However, as shown in this example ( https://imgur.com/czPEUhv ), while this method give the intended low-resolution and aliased look, it has no center of rotation, and renders the transparency color as half-transparent black.
Is there a function that does what I'm looking for? Are there some tricks to get around that?
What I would do is to render what you want to in a SDL_Texture, and then print this texture into the renderer, using something like :
// Set 'your_texture' as target
SDL_SetRenderTarget(your_renderer, your_texture);
// We are now printing the rotated image on the texture
SDL_RenderCopyEx(your_renderer, // we still use the renderer; it will be automatically printed into the texture 'your_texture'
your_image,
&srcrect,
&dstrect,
angle,
&center,
SDL_FLIP_NONE); // unless you want to flip vertically / horizontally
// Set the renderer as target and print the previous texture
SDL_SetRenderTarget(your_renderer, NULL);
SDL_RenderClear(your_renderer);
SDL_RenderCopy (your_renderer, your_texture, NULL, NULL); // here the scale is automatically done
SDL_RenderPresent(your_renderer);
It works, but I don't know if it is very efficient.
Don't forget to define your_texture with a SDL_TEXTUREACCESS_TARGET access.
Hope this helps,
Durza42
Thanks to #Durza42, here's the solution to my problem:
#define kScreenWidth 320
#define kScreenHeight 240
SDL_Window* g_window = NULL;
SDL_Texture* g_texture = NULL;
SDL_Renderer* g_renderer = NULL;
SDL_Texture* g_sprite = NULL;
double g_sprite_angle = 0.0;
SDL_FRect g_sprite_frect = {
.x = 50.0f,
.y = 50.0f,
.w = 32.0f,
.h = 32.0f,
};
void
sdl_load(void)
{
SDL_Init(SDL_INIT_VIDEO);
g_window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, kScreenWidth, kScreenHeight, 0);
g_renderer = SDL_CreateRenderer(g_window, -1, SDL_RENDERER_PRESENTVSYNC);
g_texture = SDL_CreateTexture(g_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, kScreenWidth, kScreenHeight);
SDL_RenderSetLogicalSize(g_renderer, kScreenWidth, kScreenHeight);
}
void
sprite_load(void)
{
g_sprite = IMG_LoadTexture(g_renderer, "./sprite.png");
}
void
draw(void)
{
SDL_SetRenderTarget(g_renderer, g_texture);
SDL_RenderClear(g_renderer);
SDL_RenderCopyExF(g_renderer, g_sprite, NULL, &g_sprite_frect, g_sprite_angle, NULL, SDL_FLIP_NONE);
SDL_SetRenderTarget(g_renderer, NULL);
SDL_RenderClear(g_renderer);
SDL_RenderCopy(g_renderer, g_texture, NULL, NULL);
SDL_RenderPresent(g_renderer);
}

Get texture coordinates of mouse position in SDL2?

I have the strict requirement to have a texture with resolution (let's say) of 512x512, always (even if the window is bigger, and SDL basically scales the texture for me, on rendering). This is because it's an emulator of a classic old computer assuming a fixed texture, I can't rewrite the code to adopt multiple texture sizes and/or texture ratios dynamically.
I use SDL_RenderSetLogicalSize() for the purpose I've described above.
Surely, when this is rendered into a window, I can get the mouse coordinates (window relative), and I can "scale" back to the texture position with getting the real window size (since the window can be resized).
However, there is a big problem here. As soon as window width:height ratio is not the same as the texture's ratio (for example in full screen mode, since the ratio of modern displays would not match of the ratio I want to use), there are "black bars" at the sides or top/bottom. Which is nice, since I want always the same texture ratio, fixed, and SDL does it for me, etc. However I cannot find a way to ask SDL where is my texture rendered exactly inside the window based on the fixed ratio I forced. Since I need the position within the texture only, and the exact texture origin is placed by SDL itself, not by me.
Surely, I can write some code to figure out how those "black bars" would change the origin of the texture, but I can hope there is a more simple and elegant way to "ask" SDL about this, since surely it has the code to position my texture somewhere, so I can re-use that information.
My very ugly (can be optimized, and floating point math can be avoided I think, but as the first try ...) solution:
static void get_mouse_texture_coords ( int x, int y )
{
int win_x_size, win_y_size;
SDL_GetWindowSize(sdl_win, &win_x_size, &win_y_size);
// I don't know if there is more sane way for this ...
// But we must figure out where is the texture within the window,
// which can be changed since the fixed ratio versus the window ratio (especially in full screen mode)
double aspect_tex = (double)SCREEN_W / (double)SCREEN_H;
double aspect_win = (double)win_x_size / (double)win_y_size;
if (aspect_win >= aspect_tex) {
// side ratio correction bars must be taken account
double zoom_factor = (double)win_y_size / (double)SCREEN_H;
int bar_size = win_x_size - (int)((double)SCREEN_W * zoom_factor);
mouse_x = (x - bar_size / 2) / zoom_factor;
mouse_y = y / zoom_factor;
} else {
// top-bottom ratio correction bars must be taken account
double zoom_factor = (double)win_x_size / (double)SCREEN_W;
int bar_size = win_y_size - (int)((double)SCREEN_H * zoom_factor);
mouse_x = x / zoom_factor;
mouse_y = (y - bar_size / 2) / zoom_factor;
}
}
Where SCREEN_W and SCREEN_H are the dimensions of the my texture, quite misleading by names, but anyway. Input parameters x and y are the window-relative mouse position (reported by SDL). mouse_x and mouse_y are the result, the texture based coordinates. This seems to work nicely. However, is there any sane solution or a better one?
The code which calls the function above is in my event handler loop (which I call regularly, of course), something like this:
void handle_sdl_events ( void ) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_MOUSEMOTION:
get_mouse_texture_coords(event.motion.x, event.motion.y);
break;
[...]

Reuse texture SDL

I'm making my first SDL2 game, I have a texture where I draw my game but after each rendering the texture is blanked, I need to have my original texture unmodified.
I have easily made this with surface but it was too slow.
I draw random artefacts on this texture that disappears with the time, I use SDL_RenderFill to shade the texture.
Anyone know how to do this ?
EDIT: Here's the code of the texture rendering
int gv_render(void) // This is called every 10ms
{
gv_lock;
int nexttimeout;
// Clear the screen
SDL_SetRenderTarget(renderer,NULL);
SDL_SetRenderDrawColor(renderer,0,0,0,255);
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_NONE);
SDL_RenderClear(renderer);
// Render view specific stuff
SDL_SetRenderTarget(renderer,gv_screen); // gv_screen is my screen texture
switch (player_view) { // I have multiple views
case pvsound:nexttimeout=wave_render();break; // <- THE 2ND FUNCTION \/
};
SDL_RenderPresent(renderer);
// Final screen rendering
SDL_SetRenderTarget(renderer,NULL);
SDL_RenderCopy(renderer,gv_screen,NULL,NULL);
gv_unlock;
return nexttimeout;
};
int wave_render(void) // I (will) have multiple view modes
{
game_wave *currwave = firstwave; // First wave is the first element of a linked list
game_wave *prevwave = firstwave;
map_block* block;
map_block* oldblock;
gv_lock;
// Load the old texture
SDL_RenderCopy(renderer,gv_screen,NULL,NULL);
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
// Dark the screen
SDL_SetRenderDrawColor(renderer,0,0,0,8);
SDL_RenderFillRect(renderer,NULL);
SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_NONE);
// Now I travel my list
while (currwave) {
// Apply block info
/* skipped non graphics */
// Draw the wave point
uint8_t light; // Wave have a strong that decrease with time
if (currwave->strong>=1.0)
light = 255; // Over 1 it don't decrease
else light = currwave->strong*255; // Now they aren't fully white
SDL_SetRenderDrawColor(renderer,light,light,light,255);
SDL_RenderDrawPoint(renderer, currwave->xpos,currwave->ypos);
// Switch to next wave
prevwave = currwave; // There also code is the skipped part
currwave = currwave->next;
};
SDL_RenderPresent(renderer);
gv_unlock;
return 10;
};
```
This seem to be complicated, as say #david C. Rankin the SDL renderer is faster than surface but more or less write-only (SDL_RenderReadPixels and SDL_UpdateTexture could do the job in non realtime case).
I have changed my method, I use a linked list of pixels coordinates with entry points in a 256 items array.
My source code is now :
struct game_wave_point {
struct game_wave_point *next;
int x;
int y;
};typedef struct game_wave_point game_wave_point;
game_wave_point* graph_waves[256] = {NULL,NULL,...};
wave_render(void)
{
game_wave *currwave = firstwave;
// Perform the darkening
int i;
uint8_t light;
for (i=1;i<=255;i++)
graph_waves[i-1] = graph_waves[i];
graph_waves[255] = NULL;
// Remove unvisible point
game_wave_point* newpoint;
while (graph_waves[0]) {
newpoint = graph_waves[0];
graph_waves[0] = newpoint->next;
free(newpoint);
};
// Wave heartbeat...
while (currwave) {
/* blablabla */
// Add the drawing point
newpoint = malloc(sizeof(game_wave_point));
newpoint->next = graph_waves[light];
newpoint->x = currwave->xpos*pixelsperblock;
newpoint->y = currwave->ypos*pixelsperblock;
if ((newpoint->x<0)|(newpoint->y<0))
free(newpoint);
else graph_waves[light] = newpoint;
/* blablabla */
};
// Now perform the drawing
for (i=1;i<=255;i++) {
newpoint = graph_waves[i];
SDL_SetRenderDrawColor(renderer,i,i,i,255);
SDL_GetRenderDrawColor(renderer,&light,NULL,NULL,NULL);
while (newpoint) {
SDL_RenderDrawPoint(renderer,newpoint->x,newpoint->y);
newpoint = newpoint->next;
};
};
return 10;
};
This work well on my computer (progressive slow appear in a case that I will never reach).
Next optimization maybe performed with Linux mremap(2) and similar, this will allow creating a simple array that work with SDL_RenderDrawPoints without slowness of realloc() on big array.

Mouse Movement in OpenCV

i am trying to move mouse cursor using finger coordinate in opencv. i am not able to scale it to entire screen size which 1366*768. my webcam resolution is 640*480. my mouse pointer moves only to half of the screen. i do not know why.
this is the function call:
Mouse_Move(((1366*mouse_pointer.x)/640),((768*mouse_pointer.y)/480));
and this is the implementation:
void Mouse_Move(DWORD dx,DWORD dy)
{
DWORD event=0;
event = MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;
mouse_event(event, dx*65535/Get_ScreenWidth(), dy*65535/Get_ScreenHight(), 0, 0);
}
this is my code segment.
mouse_pointer.x and mouse_pointer.y are the coordinate of my fore-finger.

opengl animations slow down when window size is increased

In many OpenGL tutorials, e.g. swiftless tutorials and many others, whenever there is an animation in the scene and the window is resized, the speed of the animation changes.
Description of strange behaviour
when the window is small, the animation speeds upwhen the window is large the animation slows downIs there an explanation for this?
#include <GL/glew.h> // Include the GLEW header file
#include <GL/glut.h> // Include the GLUT header file
bool* keyStates = new bool[256]; // Create an array of boolean values of length 256 (0-255)
bool movingUp = false; // Whether or not we are moving up or down
float yLocation = 0.0f; // Keep track of our position on the y axis.
float yRotationAngle = 0.0f; // The angle of rotation for our object
void keyOperations (void) {
if (keyStates[GLUT_KEY_LEFT]) { // If the left arrow key has been pressed
// Perform left arrow key operations
}
}
void display (void) {
keyOperations();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f); // Clear the background of our <a title="window" href="http://www.swiftless.com/tutorials/opengl/window.html">window</a> to red
glClear(GL_COLOR_BUFFER_BIT); //Clear the colour buffer (more buffers later on)
glLoadIdentity(); // Load the Identity Matrix to reset our drawing locations
glTranslatef(0.0f, 0.0f, -5.0f); // Push eveything 5 units back into the scene, otherwise we won't see the primitive
glTranslatef(0.0f, yLocation, 0.0f); // Translate our object along the y axis
glRotatef(yRotationAngle, 0.0f, 1.0f, 0.0f); // Rotate our object around the y axis
glutWireCube(2.0f); // Render the primitive
glFlush(); // Flush the OpenGL buffers to the window
if (movingUp) // If we are moving up
yLocation -= 0.005f; // Move up along our yLocation
else // Otherwise
yLocation += 0.005f; // Move down along our yLocation
if (yLocation < -3.0f) // If we have gone up too far
movingUp = false; // Reverse our direction so we are moving down
else if (yLocation > 3.0f) // Else if we have gone down too far
movingUp = true; // Reverse our direction so we are moving up
yRotationAngle += 0.005f; // Increment our rotation value
if (yRotationAngle > 360.0f) // If we have rotated beyond 360 degrees (a full rotation)
yRotationAngle -= 360.0f; // Subtract 360 degrees off of our rotation
}
void reshape (int width, int height) {
glViewport(0, 0, (GLsizei)width, (GLsizei)height); // Set our viewport to the size of our window
glMatrixMode(GL_PROJECTION); // Switch to the projection matrix so that we can manipulate how our scene is viewed
glLoadIdentity(); // Reset the projection matrix to the identity matrix so that we don't get any artifacts (cleaning up)
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 100.0); // Set the Field of view angle (in degrees), the aspect ratio of our window, and the new and far planes
glMatrixMode(GL_MODELVIEW); // Switch back to the model view matrix, so that we can start drawing shapes correctly
}
void keyPressed (unsigned char key, int x, int y) {
keyStates[key] = true; // Set the state of the current key to pressed
}
void keyUp (unsigned char key, int x, int y) {
keyStates[key] = false; // Set the state of the current key to not pressed
}
int main (int argc, char **argv) {
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode (GLUT_SINGLE); // Set up a basic display buffer (only single buffered for now)
glutInitWindowSize (500, 500); // Set the width and height of the window
glutInitWindowPosition (100, 100); // Set the position of the window
glutCreateWindow ("You’re first OpenGL Window"); // Set the title for the window
glutDisplayFunc(display); // Tell GLUT to use the method "display" for rendering
glutIdleFunc(display); // Tell GLUT to use the method "display" as our idle method as well
glutReshapeFunc(reshape); // Tell GLUT to use the method "reshape" for reshaping
glutKeyboardFunc(keyPressed); // Tell GLUT to use the method "keyPressed" for key presses
glutKeyboardUpFunc(keyUp); // Tell GLUT to use the method "keyUp" for key up events
glutMainLoop(); // Enter GLUT's main loop
}
The way this is written it uses an "as fast as possible" rendering approach. This, together with V-Sync disabled will make the animation speed depend on the time it takes to calculate the pixels of one frame. The larger the window, the more pixels there are to fill (look up the keyword fillrate).
The solution is, to measure the time between rendering frames and advance the animation by this.

Resources