[SDL] Snow with ChildWindow 자식 윈도우 눈 내리기
SDL, raylib 2025. 7. 23. 16:33 |차일드 윈도우로 화면에 내리는 눈을 만들어 보자.
// 차일드 윈도우가 100개 정도만 되어도 엄청 느려지고 잘 안된다.
// 그러다 그 이상되면 101번째 윈도우 생성시(정확히는 렌더러 생성시) 아래와 같은 Access Violation이 발생한다.
// Exception thrown at 0x00007FF8EE239D68 (nvd3dumx.dll) in SDLTest.exe: 0xC0000005 : Access violation reading location 0x0000000000000038.
// SDL3가 문제인지, 그래픽 드라이버가 문제인지... 정확히는 모르겠지만 아무래도 그래픽 드라이버 문제같다.
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stdio.h>
#include <windows.h>
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
const int number_flakes = 10;
int screen_width;
int screen_height;
SDL_Window* subwindow[number_flakes]; // 서브 윈도우
SDL_Renderer* subrenderer[number_flakes]; // 서브 윈도우 렌더러
typedef struct position {
float x, y;
float vx, vy;
} s_position;
s_position subwindow_pos[number_flakes]; // 서브 윈도우 위치
// 파티클 이미지 텍스쳐와 렉트
SDL_Texture* texture[number_flakes];
SDL_FRect rect;
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
ShowWindow(GetConsoleWindow(), SW_HIDE);
// 콘솔 창 숨김. Project - Property Pages - Linker - System - SubSystem - Windows로 바꿔서 컴파일해도 된다.
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;
}
// 부모 윈도우 생성하고 최소화
if (!SDL_CreateWindowAndRenderer("Press ESC to Quit", 320, 32, SDL_WINDOW_MINIMIZED, &window, &renderer)) {
SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
// 비트맵 로드
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, 0x00, 0x00, 0x00));
//SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapRGB(SDL_GetPixelFormatDetails(bmpSurface->format), NULL, 0x00, 0x00, 0x00));
rect = { 0, 0, (float)bmpSurface->w, (float)bmpSurface->h };
// 현재 디스플레이 정보 가져오기(해상도, 주사율 등)
const SDL_DisplayMode* displaymode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay());
screen_width = displaymode->w / 3;
screen_height = displaymode->h / 3;
for (int i = 0; i < number_flakes; i++) {
subwindow_pos[i].x = (float)SDL_rand(screen_width);
subwindow_pos[i].y = (float)SDL_rand(screen_height); // 서브 윈도우 위치 설정
subwindow_pos[i].vx = SDL_randf() * 0.5f;
subwindow_pos[i].vy = SDL_randf() + 0.8f;
/*
// 서브 윈도우 생성
SDL_PropertiesID props = SDL_CreateProperties(); // Create Properties
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TRANSPARENT_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_BORDERLESS_BOOLEAN, true);
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_ALWAYS_ON_TOP_BOOLEAN, true);
SDL_GetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, true);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, rect.w);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, rect.h);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, subwindow_pos[i].x);
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, subwindow_pos[i].y);
SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, window);
subwindow[i] = SDL_CreateWindowWithProperties(props);
if (!subwindow[i]) {
SDL_Log("Couldn't create subwindow: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
subrenderer[i] = SDL_CreateRenderer(subwindow[i], NULL);
if (!subrenderer[i]) {
SDL_Log("Couldn't create subwindow renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
*/
// 위 주석의 코드와 동일
if (!SDL_CreateWindowAndRenderer("Sub Window", (int)rect.w, (int)rect.h, SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_TRANSPARENT, &subwindow[i], &subrenderer[i])) {
SDL_Log("Couldn't create subwindow and subrenderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetWindowParent(subwindow[i], window); // 서브 윈도우 부모 설정
SDL_SetWindowPosition(subwindow[i], (int)subwindow_pos[i].x, (int)subwindow_pos[i].y);
SDL_SetRenderDrawBlendMode(subrenderer[i], SDL_BLENDMODE_BLEND);
}
for (int i = 0; i < number_flakes; i++) {
texture[i] = SDL_CreateTextureFromSurface(subrenderer[i], bmpSurface);
if (!texture[i]) {
SDL_Log("Couldn't create texture: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
}
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)
{
SDL_Delay(1000 / 60); // 60 FPS
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
for (int i = 0; i < number_flakes; i++) {
SDL_SetRenderDrawColor(subrenderer[i], 0, 0, 0, SDL_ALPHA_TRANSPARENT);
SDL_RenderClear(subrenderer[i]);
SDL_RenderTexture(subrenderer[i], texture[i], NULL, &rect);
SDL_RenderPresent(subrenderer[i]);
// 서브 윈도우 위치 업데이트
subwindow_pos[i].x += subwindow_pos[i].vx; // 오른쪽으로 이동
subwindow_pos[i].y += subwindow_pos[i].vy; // 아래로 이동
if (subwindow_pos[i].x > screen_width) {
subwindow_pos[i].x = 0; // 화면 왼쪽으로 다시 이동
}
if (subwindow_pos[i].y > screen_height) {
subwindow_pos[i].y = 0; // 화면 위로 다시 이동
}
SDL_SetWindowPosition(subwindow[i], (int)subwindow_pos[i].x, (int)subwindow_pos[i].y);
}
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
for (int i = 0; i < number_flakes; i++) {
SDL_DestroyTexture(texture[i]);
SDL_DestroyRenderer(subrenderer[i]);
SDL_DestroyWindow(subwindow[i]);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
}
'SDL, raylib' 카테고리의 다른 글
[SDL3] Parent Window Child Window Input Separation 부모 자식 윈도우 입력 구분하기 (0) | 2025.06.06 |
---|---|
[SDL3] Display Information 디스플레이 정보 가져오기 (0) | 2025.06.02 |
[raylib] Window Handle 윈도우 핸들 (0) | 2025.05.04 |
[raylib] Particle 파티클 (Snow) (0) | 2025.05.04 |
[raylib] Transparent Window(Window Flags) (0) | 2025.05.03 |