smooth pixelperfect
There is no browser build of this example yet.
Is it the same as C?
- Desktop:verified The Zig version renders a final frame that is byte-identical to the C example.
- Browser:not checked yet The browser comparison does not cover this example yet.
//! raylib [core] example - smooth pixelperfect
//!
//! Zig-API translation of examples/core/core_smooth_pixelperfect.c (raylib 6.2).
//! Example contributed by Giancamillo Alessandroni (@NotManyIdeasDev) and
//! reviewed by Ramon Santamaria (@raysan5)
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2021-2025 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5)
const rl = @import("raylib");
pub fn main() !void {
// Initialization
const screen_width = 800;
const screen_height = 450;
const virtual_screen_width = 160;
const virtual_screen_height = 90;
const virtual_ratio: f32 = @as(f32, screen_width) / @as(f32, virtual_screen_width);
rl.initWindow(screen_width, screen_height, "raylib [core] example - smooth pixelperfect");
defer rl.closeWindow(); // Close window and OpenGL context
var world_space_camera: rl.Camera2D = .{ // Game world camera
.offset = .{ .x = 0, .y = 0 },
.target = .{ .x = 0, .y = 0 },
.rotation = 0,
.zoom = 1.0,
};
var screen_space_camera: rl.Camera2D = world_space_camera; // Smoothing camera
// Load render texture to draw all our objects
const target = try rl.loadRenderTexture(virtual_screen_width, virtual_screen_height);
defer rl.unloadRenderTexture(target); // Unload render texture
const rec01: rl.Rectangle = .{ .x = 70.0, .y = 35.0, .width = 20.0, .height = 20.0 };
const rec02: rl.Rectangle = .{ .x = 90.0, .y = 55.0, .width = 30.0, .height = 10.0 };
const rec03: rl.Rectangle = .{ .x = 80.0, .y = 65.0, .width = 15.0, .height = 25.0 };
// The target's height is flipped (in the source Rectangle), due to OpenGL reasons
const source_rec: rl.Rectangle = .{
.x = 0.0,
.y = 0.0,
.width = @floatFromInt(target.texture.width),
.height = -@as(f32, @floatFromInt(target.texture.height)),
};
const window_rec: rl.Rectangle = .{
.x = (screen_width - screen_width / 1.25) / 2.0,
.y = (screen_height - screen_height / 1.25) / 2.0,
.width = screen_width / 1.25,
.height = screen_height / 1.25,
};
const overscan_rec: rl.Rectangle = .{
.x = -virtual_ratio,
.y = -virtual_ratio,
.width = screen_width + virtual_ratio * 2,
.height = screen_height + virtual_ratio * 2,
};
const origin: rl.Vector2 = .{ .x = 0.0, .y = 0.0 };
var rotation: f32 = 0.0;
var smooth_on = true;
var overscan = false;
rl.setTargetFPS(60);
// Main game loop
while (!rl.windowShouldClose()) { // Detect window close button or ESC key
// Update
rotation += 60.0 * rl.getFrameTime(); // Rotate the rectangles, 60 degrees per second
// Make the camera move to demonstrate the effect
const time: f32 = @floatCast(rl.getTime());
const camera_x = @sin(time) * 50.0 - 10.0;
const camera_y = @cos(time) * 30.0;
// Set the camera's target to the values computed above
screen_space_camera.target = .{ .x = camera_x, .y = camera_y };
// Round worldSpace coordinates, keep decimals into screenSpace coordinates
world_space_camera.target.x = @trunc(screen_space_camera.target.x);
screen_space_camera.target.x -= world_space_camera.target.x;
screen_space_camera.target.x *= virtual_ratio;
world_space_camera.target.y = @trunc(screen_space_camera.target.y);
screen_space_camera.target.y -= world_space_camera.target.y;
screen_space_camera.target.y *= virtual_ratio;
if (rl.isKeyPressed(.s)) smooth_on = !smooth_on;
if (rl.isKeyPressed(.o)) overscan = !overscan;
const dest_rec = if (overscan) overscan_rec else window_rec;
// Draw
{
rl.beginTextureMode(target);
defer rl.endTextureMode();
rl.clearBackground(.ray_white);
rl.beginMode2D(world_space_camera);
defer rl.endMode2D();
rl.drawRectanglePro(rec01, origin, rotation, .black);
rl.drawRectanglePro(rec02, origin, -rotation, .red);
rl.drawRectanglePro(rec03, origin, rotation + 45.0, .blue);
}
rl.beginDrawing();
defer rl.endDrawing();
rl.clearBackground(.light_gray);
if (smooth_on) {
rl.beginMode2D(screen_space_camera);
defer rl.endMode2D();
rl.drawTexturePro(target.texture, source_rec, dest_rec, origin, 0.0, .white);
} else {
rl.drawTexturePro(target.texture, source_rec, dest_rec, origin, 0.0, .white);
}
rl.drawText(rl.textFormat("Screen resolution: {d}x{d}", .{ screen_width, screen_height }), 10, 10, 20, .dark_blue);
rl.drawText(rl.textFormat("World resolution: {d}x{d}", .{ virtual_screen_width, virtual_screen_height }), 10, 40, 20, .dark_green);
rl.drawText(rl.textFormat("Smooth: {s}", .{if (smooth_on) "ON" else "OFF"}), 10, screen_height - 60, 20, .red);
rl.drawText(rl.textFormat("Overscan: {s}", .{if (overscan) "ON" else "OFF"}), 10, screen_height - 30, 20, .red);
rl.drawFPS(rl.getScreenWidth() - 95, 10);
}
}/*******************************************************************************************
*
* raylib [core] example - smooth pixelperfect
*
* Example complexity rating: [★★★☆] 3/4
*
* Example originally created with raylib 3.7, last time updated with raylib 4.0
*
* Example contributed by Giancamillo Alessandroni (@NotManyIdeasDev) and
* reviewed by Ramon Santamaria (@raysan5)
*
* Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
* BSD-like license that allows static linking with closed source software
*
* Copyright (c) 2021-2025 Giancamillo Alessandroni (@NotManyIdeasDev) and Ramon Santamaria (@raysan5)
*
********************************************************************************************/
#include "raylib.h"
#include <math.h> // Required for: sinf(), cosf()
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
// Initialization
//--------------------------------------------------------------------------------------
const int screenWidth = 800;
const int screenHeight = 450;
const int virtualScreenWidth = 160;
const int virtualScreenHeight = 90;
const float virtualRatio = (float)screenWidth/(float)virtualScreenWidth;
InitWindow(screenWidth, screenHeight, "raylib [core] example - smooth pixelperfect");
Camera2D worldSpaceCamera = { 0 }; // Game world camera
worldSpaceCamera.zoom = 1.0f;
Camera2D screenSpaceCamera = { 0 }; // Smoothing camera
screenSpaceCamera.zoom = 1.0f;
// Load render texture to draw all our objects
RenderTexture2D target = LoadRenderTexture(virtualScreenWidth, virtualScreenHeight);
Rectangle rec01 = { 70.0f, 35.0f, 20.0f, 20.0f };
Rectangle rec02 = { 90.0f, 55.0f, 30.0f, 10.0f };
Rectangle rec03 = { 80.0f, 65.0f, 15.0f, 25.0f };
// The target's height is flipped (in the source Rectangle), due to OpenGL reasons
Rectangle sourceRec = { 0.0f, 0.0f, (float)target.texture.width, -(float)target.texture.height };
Rectangle destRec = { (screenWidth - screenWidth/1.25f)/2.0f, (screenHeight - screenHeight/1.25f)/2.0f, screenWidth/1.25f, screenHeight/1.25f };
Vector2 origin = { 0.0f, 0.0f };
float rotation = 0.0f;
float cameraX = 0.0f;
float cameraY = 0.0f;
bool smoothOn = true;
bool overscan = false;
SetTargetFPS(60);
//--------------------------------------------------------------------------------------
// Main game loop
while (!WindowShouldClose()) // Detect window close button or ESC key
{
// Update
//----------------------------------------------------------------------------------
rotation += 60.0f*GetFrameTime(); // Rotate the rectangles, 60 degrees per second
// Make the camera move to demonstrate the effect
cameraX = (sinf((float)GetTime())*50.0f) - 10.0f;
cameraY = cosf((float)GetTime())*30.0f;
// Set the camera's target to the values computed above
screenSpaceCamera.target = (Vector2){ cameraX, cameraY };
// Round worldSpace coordinates, keep decimals into screenSpace coordinates
worldSpaceCamera.target.x = truncf(screenSpaceCamera.target.x);
screenSpaceCamera.target.x -= worldSpaceCamera.target.x;
screenSpaceCamera.target.x *= virtualRatio;
worldSpaceCamera.target.y = truncf(screenSpaceCamera.target.y);
screenSpaceCamera.target.y -= worldSpaceCamera.target.y;
screenSpaceCamera.target.y *= virtualRatio;
if (IsKeyPressed(KEY_S)) smoothOn = !smoothOn;
if (IsKeyPressed(KEY_O)) overscan = !overscan;
if (overscan)
{
destRec = (Rectangle) { -virtualRatio, -virtualRatio, screenWidth + (virtualRatio*2), screenHeight + (virtualRatio*2) };
}
else
{
destRec = (Rectangle) { (screenWidth - screenWidth/1.25f)/2.0f, (screenHeight - screenHeight/1.25f)/2.0f, screenWidth/1.25f, screenHeight/1.25f };
}
//----------------------------------------------------------------------------------
// Draw
//----------------------------------------------------------------------------------
BeginTextureMode(target);
ClearBackground(RAYWHITE);
BeginMode2D(worldSpaceCamera);
DrawRectanglePro(rec01, origin, rotation, BLACK);
DrawRectanglePro(rec02, origin, -rotation, RED);
DrawRectanglePro(rec03, origin, rotation + 45.0f, BLUE);
EndMode2D();
EndTextureMode();
BeginDrawing();
ClearBackground(LIGHTGRAY);
if (smoothOn)
{
BeginMode2D(screenSpaceCamera);
DrawTexturePro(target.texture, sourceRec, destRec, origin, 0.0f, WHITE);
EndMode2D();
}
else
{
DrawTexturePro(target.texture, sourceRec, destRec, origin, 0.0f, WHITE);
}
DrawText(TextFormat("Screen resolution: %ix%i", screenWidth, screenHeight), 10, 10, 20, DARKBLUE);
DrawText(TextFormat("World resolution: %ix%i", virtualScreenWidth, virtualScreenHeight), 10, 40, 20, DARKGREEN);
DrawText(TextFormat("Smooth: %s", (smoothOn ? "ON" : "OFF")), 10, screenHeight - 60, 20, RED);
DrawText(TextFormat("Overscan: %s", (overscan ? "ON" : "OFF")), 10, screenHeight - 30, 20, RED);
DrawFPS(GetScreenWidth() - 95, 10);
EndDrawing();
//----------------------------------------------------------------------------------
}
// De-Initialization
//--------------------------------------------------------------------------------------
UnloadRenderTexture(target); // Unload render texture
CloseWindow(); // Close window and OpenGL context
//--------------------------------------------------------------------------------------
return 0;
}From raylib 6.2. The original on GitHub.