반응형

부모 윈도우와 자식 윈도우의 입력을 구분해 처리해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#define SDL_MAIN_USE_CALLBACKS 1
 
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stdio.h>
#include <Windows.h>
 
static SDL_Window* window = NULL;
static SDL_Renderer* renderer = NULL;
 
static SDL_Window* childWindow = NULL;
static SDL_Renderer* childRenderer = NULL;
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_SetAppMetadata("Example""1.0""Sean");
 
    // Initialize SDL with video subsystem
    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // 메인 윈도우 및 렌더러 생성
    if (!SDL_CreateWindowAndRenderer("Parent Window"6404800&window, &renderer)) {
        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    printf("Main window ID: %d\n", SDL_GetWindowID(window));
 
    // 자식 윈도우 및 렌더러 생성
    if (!SDL_CreateWindowAndRenderer("Child Window"6404800&childWindow, &childRenderer)) {
        SDL_Log("Couldn't create child window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    printf("Child window ID: %d\n", SDL_GetWindowID(childWindow));
 
    // 메인 윈도우를 자식 윈도우의 부모 윈도우로 설정
    if (!SDL_SetWindowParent(childWindow, window)) {
        SDL_Log("Couldn't set child window parent: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // 윈도우 핸들 구하기
    SDL_PropertiesID prop = SDL_GetWindowProperties(window);
    HWND hwnd = (HWND)SDL_GetPointerProperty(prop, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
    if (hwnd)
        printf("Main window handle: %p\n", hwnd);
 
    prop = SDL_GetWindowProperties(childWindow);
    HWND hpwnd = (HWND)SDL_GetPointerProperty(prop, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
    if (hpwnd)
        printf("Popup window handle: %p\n", hpwnd);
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type) {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
    case SDL_EVENT_KEY_DOWN:
        printf("Key pressed window: %d, Key: %s\n", event->key.windowID, SDL_GetKeyName(event->key.key));
        if (event->key.key == SDLK_ESCAPE)
            if (event->key.windowID == SDL_GetWindowID(window))
                return SDL_APP_SUCCESS; // Exit on Escape key in main window
            else if (event->key.windowID == SDL_GetWindowID(childWindow)) {
                // 자식 윈도우에서 Escape 키를 누르면 자식 윈도우 닫음
                SDL_DestroyRenderer(childRenderer);
                childRenderer = NULL;
                SDL_DestroyWindow(childWindow);
                childWindow = NULL;
            }
        break;
    case SDL_EVENT_MOUSE_BUTTON_DOWN:
        printf("Mouse button pressed window: %d, Button index: %d\n", event->button.windowID, event->button.button);
        printf("Mouse position: (%d, %d)\n", (int)event->button.x, (int)event->button.y);
        break;
    default:
        break;
    }
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    SDL_SetRenderDrawColor(renderer, 255255255, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(renderer);
    SDL_RenderPresent(renderer);
 
    if (childRenderer)
    {
        SDL_SetRenderDrawColor(childRenderer, 00255, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(childRenderer);
        SDL_RenderPresent(childRenderer);
    }
 
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    if (childRenderer)
        SDL_DestroyRenderer(childRenderer);
    if (childWindow)
        SDL_DestroyWindow(childWindow);
 
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
 
    SDL_Quit();
}
 

 

자식 윈도우에서 ESC키를 누르면 자식 윈도우만 종료된다.

 

반응형
Posted by J-sean
:
반응형

Display number, name, format, width, height, refresh rate 등의 정보를 확인해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <SDL3/SDL.h>
 
int main() {
    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // 모든 디스플레이 정보 가져오기(해상도, 주사율 등)
    int num_displays;
    SDL_DisplayID* displays = SDL_GetDisplays(&num_displays);
    SDL_Log("Found %d display(s)\n\n", num_displays);
 
    for (int i = 0; i < num_displays; i++) {
        const SDL_DisplayMode* displaymode = SDL_GetCurrentDisplayMode(displays[i]);
        SDL_Log("Display %d: %s(width: %d, height: %d)", i, SDL_GetDisplayName(displays[i]),
            displaymode->w, displaymode->h);
    }
 
    // 위 코드보다 간단히 현재 디스플레이 정보만 가져오기(해상도, 주사율 등)
    const SDL_DisplayMode* displaymode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
    SDL_Log("\nPrimary Display: %s(width: %d, height: %d)", SDL_GetDisplayName(SDL_GetPrimaryDisplay()),
        displaymode->w, displaymode->h);
 
    SDL_Quit();
 
    return 0;
}
 

 

코드를 작성하고 빌드한다.

SDL_DisplayMode 구조체는 아래와 같이 구성되어 있다.

■ SDL_DisplayID displayID; /* the display this mode is associated with */
■ SDL_PixelFormat format; /* pixel format */
■ int w; /* width */
■ int h; /* height */
■ float pixel_density; /* scale converting size to pixels (e.g. a 1920x1080 mode with 2.0 scale would have 3840x2160 pixels) */
■ float refresh_rate; /* refresh rate (or 0.0f for unspecified) */
■ int refresh_rate_numerator; /* precise refresh rate numerator (or 0 for unspecified) */
■ int refresh_rate_denominator; /* precise refresh rate denominator */

 

실행하면 디스플레이 정보가 표시된다.

 

반응형
Posted by J-sean
:
반응형

raylib에서 윈도우 핸들을 구해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#define _CRT_SECURE_NO_WARNINGS
 
#include "raylib.h"
#include <stdio.h>
 
int main(void)
{
    InitWindow(640480"raylib example");
 
    void* p = GetWindowHandle();
    printf("Window Handle: %p\n", p);
    //printf("%016llX\n", (long long)p);
 
    char str[17];
    sprintf(str, "%016llX", (long long)p);
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
 
        ClearBackground(RAYWHITE);
        DrawText(str, 22023020, GRAY);
 
        EndDrawing();
    }
 
    CloseWindow();
 
    return 0;
}
 

 

소스를 입력하고 빌드한다.

 

마지막 줄에 윈도우 핸들이 출력된다.

 

윈도우 핸들이 출력된다.

하지만 raylib는 child window를 만들 수 없다.

 

※ 참고

2025.03.30 - [SDL, raylib] - [SDL3] Simple DirectMedia Layer 3 Setup and Getting Started - SDL3 설정 및 초기화

 

반응형
Posted by J-sean
:
반응형

raylib로 간단한 파티클 시스템을 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
class Particles {
private:
    Vector2 position;
    Vector2 velocity;
public:
    Particles() {
        Reset();
    }
 
    void Draw_particle() {
        //DrawPixel(position.x, position.y, WHITE);
        //DrawCircle(position.x, position.y, 10, WHITE);
        DrawTexture(texture, position.x, position.y, WHITE);
        position.x += velocity.x;
        position.y += velocity.y;
        if (position.x > screenWidth || position.y > screenHeight)
            Reset();
    }
 
    void Reset() {
        position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
        position.y = GetRandomValue(-screenHeight * 20);
        float max = 10000.0f;
        velocity.x = (GetRandomValue(1, (int)max) / max) * 0.5f;
        velocity.y = (GetRandomValue(1, (int)max) / max) + 0.8f;
    }
};
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    const int number_particles = 400;
    Particles particles[number_particles];
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
 
        ClearBackground(BLACK);
 
        for (int i = 0; i < number_particles; i++)
            particles[i].Draw_particle();
 
        DrawFPS(00);
 
        EndDrawing();
    }
 
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

특별한 설정 없이도 png 파일의 알파 채널을 인식한다.

소스를 입력하고 빌드한다.

 

snow.png
0.00MB

 

 

DrawPixel(position.x, position.y, WHITE) 실행

 

DrawTexture(texture, position.x, position.y, WHITE) 실행


실제 실행하면 텍스쳐가 많이 깜빡인다. (아래 동영상 참고)

DrawPixel() 을 실행할 때는 크게 눈에 띄지 않지만 DrawTexture() 를 실행하면 눈에 띈다.

 

윈도우 사이즈를 크게 할수록 깜빡이는 현상이 줄어드는거 같다. 아니면 snow.png 파일을 LoadImage()로 로드하고 ImageResize()로 크게 바꾼 다음 LoadTextureFromImage()로 로드하면 깜빡임이 약간 줄어드는거 같다. (ImageResize()로 이미지 확대가 핵심)

Vector2로 정의된 위치값을 사용하는 DrawTextureV()를 이용해도 차이가 없다.

정확한 원인을 모르겠다.

 

 

RenerTexture2D를 사용하니까 조금 덜 깜빡이는거 같기도 한데.. 아닌거 같다.

더보기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
class Particles {
private:
    Vector2 position;
    Vector2 velocity;
public:
    Particles() {
        Reset();
    }
 
    void Draw_particle() {
        //DrawPixel(position.x, position.y, WHITE);
        //DrawCircle(position.x, position.y, 10, WHITE);
        DrawTexture(texture, position.x, position.y, WHITE);
        position.x += velocity.x;
        position.y += velocity.y;
        if (position.x > screenWidth || position.y > screenHeight)
            Reset();
    }
 
    void Reset() {
        position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
        position.y = GetRandomValue(-screenHeight * 20);
        float max = 10000.0f;
        velocity.x = (GetRandomValue(1, (int)max) / max) * 0.5f;
        velocity.y = (GetRandomValue(1, (int)max) / max) + 0.8f;
    }
};
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    RenderTexture2D target = LoadRenderTexture(screenWidth, screenHeight);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    const int number_particles = 400;
    Particles particles[number_particles];
 
    while (!WindowShouldClose())
    {
        BeginTextureMode(target);
        {
            ClearBackground(BLACK);
 
            for (int i = 0; i < number_particles; i++)
                particles[i].Draw_particle();
 
            DrawFPS(00);
        }
        EndTextureMode();
 
        BeginDrawing();
        {
            //ClearBackground(BLACK);
            //DrawTexture(target.texture, 0, 0, WHITE); // 위아래가 뒤집혀 보인다.
            DrawTextureRec(target.texture, { 00, screenWidth, -screenHeight }, { 00 }, WHITE);
            // OpenGL의 좌표 체계가 다르기 때문에 위아래를 뒤집어야 제대로 표시된다.
        }
        EndDrawing();
    }
 
    UnloadTexture(texture);
    UnloadRenderTexture(target);
 
    CloseWindow();
 
    return 0;
}
 

 

 

Raylib 파티클 예제에 나오는 것 처럼 구조체를 이용해 봐도 별 차이가 없다.

Raylib Particles  

더보기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
typedef struct {
    Vector2 position;
    Vector2 velocity;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
void spawn_particle(s_particle* pt) {
    pt->position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
    pt->position.y = GetRandomValue(-screenHeight * 20);
    float max = 10000.0f;
    pt->velocity.x = (GetRandomValue(1, (int)max) / max) * 0.5f;
    pt->velocity.y = (GetRandomValue(1, (int)max) / max) + 0.8f;
}
 
void draw_particle(s_particle pt[]) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &pt[i];
        particle->position.x += particle->velocity.x;
        particle->position.y += particle->velocity.y;
 
        if (particle->position.x > screenWidth || particle->position.y > screenHeight)
            spawn_particle(particle);
 
        DrawTexture(texture, particle->position.x, particle->position.y, WHITE);
    }
}
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
        {
            ClearBackground(BLACK);
 
            draw_particle(particles);
 
            DrawFPS(00);
        }
        EndDrawing();
    }
 
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

한 가지 확인한 것은 velocity->x, velocity->y의 값을 임의의 소수가 아닌 (1이나 2같은)정수로 바꾸면 깜빡임이 없다.

Raylib 렌더링 함수에서 소수 처리 부분에 문제가 있는게 아닐까 싶다.

 

매 프레임마다 눈 이동 거리를 delta time으로 계산해도 별 의미가 없는거 같다.

더보기

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include "raylib.h"
 
const int screenWidth = 640;
const int screenHeight = 480;
 
Texture2D texture;
 
typedef struct {
    Vector2 position;
    Vector2 velocity;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
void spawn_particle(s_particle* pt) {
    pt->position.x = GetRandomValue(-screenWidth * 0.4f, screenWidth);
    pt->position.y = GetRandomValue(-screenHeight * 20);
    //float max = 10000.0f;
    //pt->velocity.x = (float)(GetRandomValue(1, (int)max) / max) * 0.5f;
    //pt->velocity.y = (float)(GetRandomValue(1, (int)max) / max) + 0.8f;
 
    pt->velocity.x = (float)GetRandomValue(030+ 10;
    // 눈이 오른쪽으로 이동하는 속도를 초당 10~40 픽셀로 설정
    pt->velocity.y = (float)GetRandomValue(2080+ 40;
    // 눈이 아래로 떨어지는 속도를 초당 60~120 픽셀로 설정    
}
 
void draw_particle(s_particle pt[], float delta) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &pt[i];
        particle->position.x += particle->velocity.x * delta;
        particle->position.y += particle->velocity.y * delta;
 
        if (particle->position.x > screenWidth || particle->position.y > screenHeight)
            spawn_particle(particle);
 
        DrawTexture(texture, particle->position.x, particle->position.y, WHITE);
    }
}
 
int main(void)
{
    //SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    // InitWindow() 실행시 내부에서 SetRandomSeed()를 time(NULL)로 초기화 한다.
    // particle 생성시 GetRandomValue()를 사용하므로 InitWindow() 이후에 생성한다.
    SetTargetFPS(60);
 
    texture = LoadTexture("snow.png");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
        {
            ClearBackground(BLACK);
 
            draw_particle(particles, GetFrameTime());
            // GetFrameTime() : Get time in seconds for last frame drawn (delta time)
 
            DrawFPS(00);
        }
        EndDrawing();
    }
 
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

 

반응형
Posted by J-sean
:
반응형

투명한 윈도우를 만들어 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "raylib.h"
 
int main(void)
{
    const int screenWidth = 450;
    const int screenHeight = 500;
 
    SetConfigFlags(FLAG_WINDOW_TRANSPARENT | FLAG_WINDOW_UNDECORATED);
    InitWindow(screenWidth, screenHeight, "raylib example");
    SetTargetFPS(60);
 
    Image rayimage = LoadImage("palvin.jpg");
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
    Texture2D texture = LoadTextureFromImage(rayimage);
 
    //Texture2D texture = LoadTexture("palvin.jpg");
    // Image 사용 없이 LoadTexture("palvin.jpg")로 해도 된다.
    // 이 경우, 아래 UnloadImage(rayimage);는 삭제한다.
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
 
        ClearBackground(BLANK);
 
        DrawTexture(texture, 1010, WHITE);
 
        EndDrawing();
    }
 
    UnloadImage(rayimage);
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

소스를 입력하고 빌드한다.

 

타이틀바가 없고 배경이 투병한 윈도우에 이미지가 출력된다.

 

Window Flags

 

반응형

'SDL, raylib' 카테고리의 다른 글

[raylib] Window Handle 윈도우 핸들  (0) 2025.05.04
[raylib] Particle 파티클 (Snow)  (0) 2025.05.04
[raylib] raylib with opencv  (0) 2025.05.03
[raylib] raylib 설정하고 사용하기  (0) 2025.05.02
[SDL3] Framerate Per Second FPS  (0) 2025.04.22
Posted by J-sean
:
반응형

raylib와 opencv를 사용해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include "raylib.h"
#include "opencv2/opencv.hpp"
 
using namespace cv;
 
int main(void)
{
    Mat cvimage = imread("palvin.jpg", IMREAD_COLOR_RGB);
 
   Image rayimage{};
    rayimage.width = cvimage.cols;
    rayimage.height = cvimage.rows;
    rayimage.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8;
    rayimage.mipmaps = 1;
    rayimage.data = cvimage.ptr(); //(void*)(cvimage.data);
 
    const int screenWidth = 450;
    const int screenHeight = 500;
    InitWindow(screenWidth, screenHeight, "raylib example");
    SetTargetFPS(60);
 
    // NOTE: Textures MUST be loaded after Window initialization (OpenGL context is required)
    Texture2D texture = LoadTextureFromImage(rayimage);
 
    while (!WindowShouldClose())
    {
        BeginDrawing();
 
        ClearBackground(RAYWHITE);
 
        DrawTexture(texture, 1010, WHITE);
 
        EndDrawing();
    }
 
    //UnloadImage(rayimage);
    // LoadImage()로 로드한 이미지에만 사용.
    UnloadTexture(texture);
 
    CloseWindow();
 
    return 0;
}
 

 

raylib에서 texture는 윈도우가 생성된 이후 로드되어야 한다.

 

 

반응형
Posted by J-sean
:
반응형

raylib를 다운받고 아래와 같이 프로젝트를 설정한다.

 

  • Project Property Pages - Debugging - Environment - path=D:\raylib\lib
  • Project Property Pages - C/C++ - General - Additional Include Directories - D:\raylib\include
  • Project Property Pages - Linker - General - Additional Library Directories - D:\raylib\lib
  • Project Property Pages - Linker - Input - Additional Dependencies - raylib.lib;winmm.lib
  • Project Property Pages - Linker - Input - Ignore Specific Default Libraries - msvcrt.lib

 

※ Debug 모드에서 msvcrt.lib를 Ignore Specific Default Libraries에 넣지 않으면 아래와 같은 경고가 발생한다. (Release 모드에서는 넣으면 안된다. 에러가 발생한다.)

LINK : warning LNK4098: defaultlib 'MSVCRT' conflicts with use of other libs; use /NODEFAULTLIB:library

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "raylib.h"
 
//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
    // Initialization
    //--------------------------------------------------------------------------------------
    const int screenWidth = 800;
    const int screenHeight = 450;
 
    InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
 
    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
    //--------------------------------------------------------------------------------------
 
    // Main game loop
    while (!WindowShouldClose())    // Detect window close button or ESC key
    {
        // Update
        //----------------------------------------------------------------------------------
        // TODO: Update your variables here
        //----------------------------------------------------------------------------------
 
        // Draw
        //----------------------------------------------------------------------------------
        BeginDrawing();
 
        ClearBackground(RAYWHITE);
 
        DrawText("Congrats! You created your first window!"19020020, LIGHTGRAY);
 
        EndDrawing();
        //----------------------------------------------------------------------------------
    }
 
    // De-Initialization
    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------
 
    return 0;
}
 

 

코드를 입력하고 빌드한다.

 

실행하면 윈도우가 나타난다.

 

아래 예제 코드를 참고한다.

Examples(Github)

Examples(Homepage)

FAQ

Cheatsheet

raylib wiki

 

반응형

'SDL, raylib' 카테고리의 다른 글

[raylib] Transparent Window(Window Flags)  (0) 2025.05.03
[raylib] raylib with opencv  (0) 2025.05.03
[SDL3] Framerate Per Second FPS  (0) 2025.04.22
[SDL3] Snapshot(Screenshot) 스냅샷  (0) 2025.04.20
[SDL3] Particle 파티클 (Fireworks/Snow)  (0) 2025.04.18
Posted by J-sean
:
반응형

SDL 사용시 FPS를 고정해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stdio.h>
 
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
 
int screen_width = 640;
int screen_height = 480;
 
Uint64 start;
Uint64 end;
float fps;
 
typedef struct {
    float x, y;
    float vx, vy;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
// 파티클 이미지 텍스쳐와 렉트
SDL_Texture* texture;
SDL_FRect rect;
 
void spawn_particle(s_particle* pt) {
    pt->= (SDL_randf() * 2 - 1* screen_width * 10;
    pt->= SDL_randf() * screen_height * -2;
    // 넓은 범위에서 눈이 생성되게 해서 실행 초기에 눈이 쏟아져 내리는걸 방지.
    pt->vx = SDL_randf() * 0.5f; // 눈은 오른쪽으로만 흩날린다.
    pt->vy = SDL_randf() + 0.8f;
}
 
void draw_particle(s_particle pt[]) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &pt[i];
        particle->+= particle->vx;
        particle->+= particle->vy;
        // 눈이 화면 왼쪽에서도 바람에 날려 올 수 있도록 생존 범위 조정.
        if (particle->> screen_width || particle->< -screen_width || particle->> screen_height)
            spawn_particle(particle);
 
        // 텍스쳐 그리기
        rect.x = particle->- rect.w / 2;
        rect.y = particle->- rect.h / 2;
        SDL_RenderTexture(renderer, texture, NULL&rect);
 
        //SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
        //SDL_RenderPoint(renderer, particle->x, particle->y);
    }
}
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_SetAppMetadata("Example""1.0""sean");
 
    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
    // A variable controlling whether updates to the SDL screen surface should be synchronized
    // with the vertical refresh, to avoid tearing.
 
    if (!SDL_CreateWindowAndRenderer("example", screen_width, screen_height, 0&window, &renderer)) {
        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    // 비트맵 로드
    SDL_Surface* bmpSurface = SDL_LoadBMP("snow.bmp");
    if (!bmpSurface) {
        SDL_Log("Couldn't load BMP: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // 컬러키(투명) 설정
    SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapSurfaceRGB(bmpSurface, 0x000x000x00));
    //SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapRGB(SDL_GetPixelFormatDetails(bmpSurface->format), NULL, 0x00, 0x00, 0x00));
    rect = { 00, (float)bmpSurface->w, (float)bmpSurface->h };
    texture = SDL_CreateTextureFromSurface(renderer, bmpSurface);
 
    SDL_DestroySurface(bmpSurface);
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type) {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
    case SDL_EVENT_KEY_DOWN:
        printf("Key pressed: %s\n", SDL_GetKeyName(event->key.key));
        if (event->key.key == SDLK_ESCAPE)
            return SDL_APP_SUCCESS;
        break;
    default:
        break;
    }
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    start = SDL_GetPerformanceCounter();
 
    {
        SDL_SetRenderDrawColor(renderer, 000, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
 
        draw_particle(particles);
 
        SDL_RenderPresent(renderer);
    }
 
    end = SDL_GetPerformanceCounter();
    fps = 1.0f / ((end - start) / (float)SDL_GetPerformanceFrequency());
    printf("FPS: %f\n", fps);
 
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    SDL_DestroyTexture(texture);
 
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}
 

 

 

위 내용은 눈 내리는 코드와 실행 결과이다. FPS를 고정하기 위해 SDL_AppInit()에서 수직 동기화(Vertical Synchronization)를 설정했다. 특정 FPS를 간단히 지정하고 싶다면 아래와 같이 해도 된다.

SDL_Delay(1000 / 원하는 FPS)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SDL_AppResult SDL_AppIterate(void* appstate)
{
    start = SDL_GetPerformanceCounter();
    SDL_Delay(1000 / 60);
 
    {
        SDL_SetRenderDrawColor(renderer, 000, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
 
        draw_particle(particles);
 
        SDL_RenderPresent(renderer);
    }
 
    end = SDL_GetPerformanceCounter();
    fps = 1.0f / ((end - start) / (float)SDL_GetPerformanceFrequency());
    printf("FPS: %f\n", fps);
 
    return SDL_APP_CONTINUE;
}
 

 

 

아니면 SDL3_gfx 라이브러리를 사용할 수도 있다. 아래 링크에서 다운로드하자.

SDL3_gfx

SDL3_gfx-1.0.1.zip
4.99MB

 

 

여기서는 FPS관련 파일만 프로젝트에 추가한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stdio.h>
#include "SDL3_framerate.h"
 
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
 
int screen_width = 640;
int screen_height = 480;
 
Uint64 start;
Uint64 end;
float fps;
 
// FPS 관리자
FPSmanager fpsm;
 
typedef struct {
    float x, y;
    float vx, vy;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
// 파티클 이미지 텍스쳐와 렉트
SDL_Texture* texture;
SDL_FRect rect;
 
void spawn_particle(s_particle* pt) {
    pt->= (SDL_randf() * 2 - 1* screen_width * 10;
    pt->= SDL_randf() * screen_height * -2;
    // 넓은 범위에서 눈이 생성되게 해서 실행 초기에 눈이 쏟아져 내리는걸 방지.
    pt->vx = SDL_randf() * 0.5f; // 눈은 오른쪽으로만 흩날린다.
    pt->vy = SDL_randf() + 0.8f;
}
 
void draw_particle(s_particle pt[]) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &pt[i];
        particle->+= particle->vx;
        particle->+= particle->vy;
        // 눈이 화면 왼쪽에서도 바람에 날려 올 수 있도록 생존 범위 조정.
        if (particle->> screen_width || particle->< -screen_width || particle->> screen_height)
            spawn_particle(particle);
 
        // 텍스쳐 그리기
        rect.x = particle->- rect.w / 2;
        rect.y = particle->- rect.h / 2;
        SDL_RenderTexture(renderer, texture, NULL&rect);
 
        //SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
        //SDL_RenderPoint(renderer, particle->x, particle->y);
    }
}
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_SetAppMetadata("Example""1.0""sean");
 
    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // FPS 관리자 초기화. FPS=60
    SDL_initFramerate(&fpsm);
    SDL_setFramerate(&fpsm, 60);
    printf("Set FPS: %d\n", SDL_getFramerate(&fpsm));
 
    if (!SDL_CreateWindowAndRenderer("example", screen_width, screen_height, 0&window, &renderer)) {
        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    // 비트맵 로드
    SDL_Surface* bmpSurface = SDL_LoadBMP("snow.bmp");
    if (!bmpSurface) {
        SDL_Log("Couldn't load BMP: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // 컬러키(투명) 설정
    SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapSurfaceRGB(bmpSurface, 0x000x000x00));
    //SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapRGB(SDL_GetPixelFormatDetails(bmpSurface->format), NULL, 0x00, 0x00, 0x00));
    rect = { 00, (float)bmpSurface->w, (float)bmpSurface->h };
    texture = SDL_CreateTextureFromSurface(renderer, bmpSurface);
 
    SDL_DestroySurface(bmpSurface);
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type) {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
    case SDL_EVENT_KEY_DOWN:
        printf("Key pressed: %s\n", SDL_GetKeyName(event->key.key));
        if (event->key.key == SDLK_ESCAPE)
            return SDL_APP_SUCCESS;
        break;
    default:
        break;
    }
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    start = SDL_GetPerformanceCounter();
 
    {
        SDL_SetRenderDrawColor(renderer, 000, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
 
        draw_particle(particles);
 
        SDL_RenderPresent(renderer);
    }
 
    // FPS를 맞추기 위한 지연.
    SDL_framerateDelay(&fpsm);
 
    end = SDL_GetPerformanceCounter();
    fps = 1.0f / ((end - start) / (float)SDL_GetPerformanceFrequency());
    printf("Actual FPS: %f\n", fps);
 
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    SDL_DestroyTexture(texture);
 
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}
 

 

 

프로그램을 실행하면 FPS가 60에 가깝게 유지된다.

 

SDL_AppInit()에서 FPS 관리자 초기화 부분을 제일 아래로 옮기면 최초 FPS가 좀 더 낮은 수치가 되지만 별 의미는 없는거 같다.

 

반응형

'SDL, raylib' 카테고리의 다른 글

[raylib] raylib with opencv  (0) 2025.05.03
[raylib] raylib 설정하고 사용하기  (0) 2025.05.02
[SDL3] Snapshot(Screenshot) 스냅샷  (0) 2025.04.20
[SDL3] Particle 파티클 (Fireworks/Snow)  (0) 2025.04.18
[SDL3] SDL3 Popup Window  (0) 2025.04.13
Posted by J-sean
: