Simple Stretched Raylib Fullscreen Option? - c

The code for a simple Raylib program is listed below (based on the Raylib example shapes_logo_raylib). Running the program shows a version of the Raylib logo: a black square outline which fills about a third of the (800x450) window.
It's not hard to make a fullscreen version of the program, with calls such as GetCurrentMonitor(), SetWindowSize(), GetMonitorWidth(), GetMonitorHeight()
SetConfigFlags(FLAG_WINDOW_RESIZABLE), or ToggleFullscreen(). But then, while the black square remains a similar size as before, it occupies (top left) a much smaller proportion of the larger (fullscreen) window. Is there an option to display a larger "stretched" version of the original windowed image on the fullscreen window?
#include "raylib.h"
int main(void)
{
InitWindow(800, 450, "raylib [shapes] example - raylib logo using shapes");
while (!WindowShouldClose())
{
BeginDrawing()
ClearBackground(RAYWHITE);
DrawRectangle(screenWidth/2 - 128, screenHeight/2 - 128, 256, 256, BLACK);
DrawRectangle(screenWidth/2 - 112, screenHeight/2 - 112, 224, 224, RAYWHITE);
DrawText("raylib", screenWidth/2 - 44, screenHeight/2 + 48, 50, BLACK);
EndDrawing();
}
CloseWindow();
return 0;
}

I made the following additions to your code to make it work on any window size. It draws the stuff you want to draw onto a RenderTexture2D and then draws said texture onto the screen. I've only tested it with resizable windows, but it should work in any window mode, including exclusive fullscreen.
In short:
Request render texture using LoadRenderTexture(int, int)
Use BeginTextureMode(RenderTexture2D) and EndTextureMode() to draw onto the texture
Draw the texture using DrawTexturePro(Texture2D, Rectangle, Rectangle, Vector2, float, Color), the first rectangle is the size of the texture, the second the size of the screen. If it looks mirrored, invert the height of the input texture.
Unload the render texture when done.
I added comments to all my additions/changes to highlight what needs to be changed.
#include "raylib.h"
// This was just missing from your code, but I wanted to show a compilable version of the code
int screenWidth = 800;
int screenHeight = 450;
int main(void)
{
InitWindow(800, 450, "raylib [shapes] example - raylib logo using shapes");
// This should use the flag FLAG_FULLSCREEN_MODE which results in a possible ToggleFullscreen() call later on
SetWindowState(FLAG_WINDOW_RESIZABLE);
// Request a texture to render to. The size is the screen size of the raylib example.
RenderTexture2D renderTexture = LoadRenderTexture(screenWidth, screenHeight);
while (!WindowShouldClose())
{
// Instead of using BeginDrawing() we render to the render texture. Everything else stays unchanged
BeginTextureMode(renderTexture);
ClearBackground(RAYWHITE);
DrawRectangle(screenWidth / 2 - 128, screenHeight / 2 - 128, 256, 256, BLACK);
DrawRectangle(screenWidth / 2 - 112, screenHeight / 2 - 112, 224, 224, RAYWHITE);
DrawText("raylib", screenWidth / 2 - 44, screenHeight / 2 + 48, 50, BLACK);
// We need to end the texture mode separately
EndTextureMode();
// Let's draw the texture. The source rect is the size of the texture, the destination rect is of the same size as the screen. For some reason, the texture was flipped vertically, so I had to invert the source rects "height" to flip the UV.
BeginDrawing();
DrawTexturePro(
renderTexture.texture,
Rectangle{ 0, 0, static_cast<float>(renderTexture.texture.width), static_cast<float>(-renderTexture.texture.height) },
Rectangle{ 0, 0, static_cast<float>(GetScreenWidth()), static_cast<float>(GetScreenHeight()) },
Vector2{ 0, 0 },
0,
WHITE);
EndDrawing();
}
// Unload the texture handle again to make a clean exit.
UnloadRenderTexture(renderTexture);
CloseWindow();
return 0;
}
I hope this answers your question.

Related

sdl2 flickering unless I don't use createrenderer

I have a somewhat basic rendering loop which blits a scaled image to the screen as fast as I can process the event loop. I created a minimal example that recreates the flickering on pastebin here.
If I don't use "SDL_CreateRenderer", and instead leave renderer to NULL, it works. I just can't clear the screen first. If I set the renderer, I get this crazy fast flickering.
// if I comment this out in my init_sdl(), no flickering...
renderer = SDL_CreateRenderer(window, -1, 0);
assert(renderer != NULL);
my draw function happens at the end of the event loop:
void draw()
{
SDL_SetRenderDrawColor(renderer, 255, 0, 128, 255);
SDL_RenderClear(renderer);
SDL_Rect dstrect = {
.x = 50,
.y = 50,
.h = 100,
.w = 100,
};
SDL_BlitScaled(img, NULL, screen, &dstrect);
SDL_UpdateWindowSurface(window);
SDL_RenderPresent(renderer);
}
I've seen this potential duplicate question, but the problem was that they had their RenderPresent in the wrong place. You can see I'm calling SDL_RenderPresent at the end of all drawing operations, which was my takeaway from that. It is still happening.
I'm using msys2 (mingw_x64), gcc, windows 10, SDL2.

Changing the color of certain pixels on a texture with SDL2

I'm making a game with SDL2. I have a sprite sheet that I'm loading as a texture, and I'm drawing sprites off it onto the game window, like this:
SDL_RenderCopy(renderer, sprite_sheet_texture, &src_rect, &dst_rect);
SDL_RenderPresent(renderer);
I want to specifically modify the color of every black pixels of every sprite in the texture during gameplay. Essentially I want to create a continuous glowing effect over time from black, to white, to black again.
Here's an example of what a sprite looks like in the game
Here's what the effect I'm hoping to achieve looks like
The only way I've found I could use is to read the pixel data from the sprite sheet texture and manually update the color of every black pixel to a lighter shade. Then do it again and update that lighter pixel color to an even lighter one until the lightest has been reached, and repeat the process backwards.
The code (for just the first step of black pixels -> lighter shade at least) would look something like this:
Uint32* pixels;
int pitch;
SDL_LockTexture(sprite_sheet_texture, NULL, &pixels, &pitch);
SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGBA8888, pixels, pitch);
// Get pixel count
SDL_PixelFormat* mapping_format = SDL_AllocFormat(SDL_PIXELFORMAT_RGBA8888);
int pixel_count = (pitch / mapping_format->BytesPerPixel) * sprite_sheet_height;
// Swap every black pixel to a lighter shade
Uint32 from_pixel = SDL_MapRGBA(0, 0, 0, 255);
Uint32 to_pixel = SDL_MapRGBA(24, 24, 24, 255);
for (int i = 0; i < pixel_count; i++) {
if (pixels[i] == from_pixel} {
pixels[i] = to_pixel;
}
}
SDL_FreeFormat(mapping_format);
SDL_UnlockTexture(streaming_texture);
There's a couple of problems with this method:
It's slow. I haven't tested it yet, but the SDL documentation warns against using SDL_RenderReadPixels frequently as it's a "very slow operation". I would have to run the above code multiple times per second.
My sprite sheet would be unable to have certain pixel values within it. For example, if I'm updating pixels from "0, 0, 0" to "24, 24, 24" and then to "48, 48, 48", I'll have to make sure the sprite sheet does not have a single pixel with the values "24, 24, 24" or "48, 48, 48" since the above function would also update those pixels, while I just want to update the ones that were originally black.
Is there a better way to accomplish this?

Blank screen after rendering text

I have opened a window which shows two rects on the screen then using SDL_TTF to show the mouse position on the screen.
The bit I am having hard time understanding is why after rendering text the the two rects before it do not show up.
I am using SDL_RenderFillRect to draw two rects on screen
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
SDL_RenderFillRect(renderer, rect1);
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_RenderFillRect(renderer, rect2);
Code for rendering the text is
// define string with mouse x, y coords
sprintf(someString, "x: %d, y: %d", mouse.x, mouse.y);
SDL_Point textPos = {10, 10};
WriteText(renderer, font, someString, textPos, (SDL_Color){255, 255, 255, 255});
SDL_Surface *fontSurface = TTF_RenderText_Blended(font, someString, COLOR_BLACK); // create font surface
SDL_Texture *fontTexture = SDL_CreateTextureFromSurface(renderer, fontSurface); // create the texture
// get clip width and height from fontsurface clip rect
SDL_Rect *fontRect = &fontSurface->clip_rect;
fontRect->x = pos.x;
fontRect->y = pos.y;
SDL_RenderCopy(renderer, fontTexture, NULL, fontRect); // copy text to the renderer
// delete surface and texture
SDL_FreeSurface(fontSurface);
SDL_DestroyTexture(fontTexture);
It to shows the mouse positon top left corner of the window. However this makes the rest of the window blank.
To prevent this my work around is having to draw something on the screen after calling SDL_RendererCopy (and weirdly before calling SDL_DestroyTexture too) For example drawing single point
...
SDL_RenderCopy(renderer, fontTexture, NULL, fontRect); // copy text to the renderer
// why is this needed??
SDL_RenderDrawPoint(renderer, 0, 0);
// delete surface and texture
SDL_FreeSurface(fontSurface);
SDL_DestroyTexture(fontTexture); // have to draw a point before this
...
This then shows the two rects rendered before the text
If I set dstRect to NULL when calling SDL_RenderCopy then the text spans the whole window but I can see what was rendered before underneath the text.
Why am I having to draw a point after calling SDL_RenderCopy to stop what was rendered before from not showing up?
NOTE: Link to full source code https://pastebin.com/tRSFT0PV
This is a bug in SDL 2.0.10. It's fixed by https://hg.libsdl.org/SDL/rev/6ee12b88beed and this fix will ship with 2.0.11. Sorry about that!

Keeping elements on top using winapi

I've written a little app in winapi which draws animated background like so:
case WM_PAINT:
SelectObject(canvas, images[frame]);
StretchBlt(hdc, 0, 0, 640, 320, canvas, 0, 0, 64, 32, SRCCOPY);
break;
case WM_TIMER:
SelectObject(canvas, images[frame]);
StretchBlt(hdc, 0, 0, 640, 320, canvas, 0, 0, 64, 32, SRCCOPY);
frame += 1;
if (frame == sizeof(images)/sizeof(images[0]))
frame = 0;
break;
It works flawlessly but generates some problems when it comes to drawing other elements. I got some labels in the same window.
Right after first frame is drawn in WM_PAINT labels are still visible. When I replace canvas' (HDC canvas = CreateCompatibleDC(hdc)) image with second frame (in WM_TIMER), labels suddenly disappear - I guess they stay under that new layer that is drawn.
Is there any way to keep some elements always on top or bring them to top right after I redraw the bitmap?

Cairo image blurred when scaled

I have the following cairo code:
cairo_set_source_rgba(cr, 1, 1, 1, 1);
cairo_rectangle(cr, 0, 0, WINDOW_SIZE, WINDOW_SIZE);
cairo_fill(cr);
cairo_scale(cr, 8, 8);
draw_image(cr, "q.png", 5, 5);
And
void draw_image(cairo_t* cr, char* img_name, int x, int y)
{
cairo_translate(cr, x, y);
cairo_surface_t* img = cairo_image_surface_create_from_png(img_name);
cairo_set_source_surface(cr, img, 0, 0);
cairo_paint(cr);
cairo_translate(cr, -x, -y);
}
q.png is a 5x5 image:
But when the program is run, the image is slightly blurred:
I have already tried
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
but it does not work.
Is there any way to fix this problem?
This is because of how the image is scaled up. Instead of setting a source surface directly, create a pattern out of the surface with cairo_pattern_create_for_surface(), call cairo_pattern_set_filter() on it to set the scaling mode, and then call cairo_set_source() to load the pattern. See the documentation for cairo_filter_t for the scaling modes. CAIRO_FILTER_NEAREST, for example, will give you a normal pixel zoom with no blurring or other transformations.

Resources