Nội dung bài viết
STDIO Với những engine như cocos2dx, hay unity thì việc load hình ảnh lên màn hình khá là dễ dàng, nhưng đối với framework SDL thì khá là phức tạp. Trong phạm vi bài viết này tôi sẽ hướng dẫn các bạn load hình ảnh lên màn hình sử dụng framework SDL (Simple DirectMedia Layer).

Giới thiệu

Với những engine như cocos2dx, hay unity thì việc load hình ảnh lên màn hình khá là dễ dàng, nhưng đối với framework SDL thì khá là phức tạp. Trong phạm vi bài viết này tôi sẽ hướng dẫn các bạn load hình ảnh lên màn hình sử dụng framework SDL (Simple DirectMedia Layer).

Tiền đề bài viết

Tiếp nối những bài viết hướng dẫn lập trình với framework SDL (Simple DirectMedia Layer).

Đối tượng hướng đến

Những lập trình viên đã có kiến thức vững chắc về ngôn ngữ lập trình C++, mong muốn xây dựng game cơ bản sử dụng framework SDL.

Các đối tượng sử dụng trong bài viết

SDL_Window: là struct giữ tất cả các thông tin của cửa sổ mà chúng ta tạo ra như size, postion, border, fullscreen.

SDL_Renderer: là struct xử lý tất cả các công việc rendering lên cửa sổ.

SDL_Surface: chứa một tập hợp các pixel (a collection of pixels) để có thể render lên cửa sổ sử dụng software rendering (CPU).

SDL_Texture: chứa một tập hợp các pixel (a collection of pixels) để có thể render lên cửa sổ sử dụng hardware rendering (GPU).

SDL_Rect: là struct đại diện cho một hình chữ nhật gồm có các thông tin là x, y, w, h.

Tạo đối tượng SDL_Texuture

Tôi tiếp tục sử dụng project ở bài viết Xử Lý Sự Kiện Trong SDL nhưng chỉ lại giữ lại main loopmain event. Và tiếp tục khai báo thêm một số biến sử dụng trong chương trình là renderer, tempSurface, texture, sourceRect, desRect.

int main()
{

	SDL_Window* window = NULL;
	SDL_Renderer* renderer = NULL;
	SDL_Surface* tempSurface = NULL;
	SDL_Texture* texture = NULL;
	SDL_Event mainEvent;
    SDL_Rect sourceRect;
    SDL_Rect desRect;
	bool isRunning = true;

	//initializes  the subsystems
	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
	{
		printf("Unable to initialize SDL %s\n", SDL_GetError());
		return -1;
	}

	//Create window
	window = SDL_CreateWindow("Stdio.vn - SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, SDL_WINDOW_SHOWN);
	if (window == NULL)
	{
		printf("Could not create window %s", SDL_GetError());
		return -1;
	}
	//main loop
	while (isRunning)
	{
		//main event
		while (SDL_PollEvent(&mainEvent))
		{
			switch (mainEvent.type)
			{
				//User - requested quit
				case SDL_QUIT:
				{
					isRunning = false;
					break;
				}
                default:
                {
                    break;
                }
            }
		}
	}

	//Destroy a window.
	SDL_DestroyWindow(window);

	//cleans up all initialized subsystems
	SDL_Quit();
	return 0;
}

Tạo đối tượng renderer để có thể render lên cửa sổ bằng cách:

renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
if (renderer == NULL)
{
	printf("Could not create render %s", SDL_GetError());
	return -1;
}

Tiếp theo tạo tempSurface từ một file hình có đuôi mở rộng là .bmp và tạo texture từ tempSurface đó. Sau đó hủy tempSurface. Ở đây file hình ảnh của tôi có tên là "texture_demo.bmp" được đặt trong thư mục gốc của solution.

tempSurface = SDL_LoadBMP("texture_demo.bmp");
texture = SDL_CreateTextureFromSurface(renderer, tempSurface);
SDL_FreeSurface(tempSurface);

Lưu ý: Hàm SDL_LoadBMP() chỉ nhận được hình ảnh có đuôi mở rộng là .bmp.

Sử dụng hàm SDL_QueryTexture() để lấy ra thông tin chiều rộng và chiều cao của texture.

SDL_QueryTexture(texture, NULL, NULL, &sourceRect.w, &sourceRect.h);

Ở trên tôi có tạo khai báo đối tượng SDL_Rect là sourceRect và desRect. Chức năng của chúng như sau:

sourceRect: sử dụng để thông tin về chiều cao, chiều rộng của texture ta muốn vẽ. Ví dụ ta có một texture được load lên. Nhưng ta không muốn vẽ toàn bộ texture đó lên mà hình mà ta chỉ muốn vẽ một phần nào đó của texture này mà thôi, ta sẽ sử dụng đối tượng hình chữ nhật này để fix lại x, y, w, h.

desRect: sử dụng để xác định tọa độ của texture mà ta muốn vẽ trên màn hình.

Vẽ Texture lên màn hình

Lấy thông tin về chiều cao và chiều rộng của texture sau khi texure được tạo:

SDL_QueryTexture(texture, NULL, NULL, &sourceRect.w, &sourceRect.h);

sourceRect.x = desRect.x = 0;
sourceRect.y = desRect.y = 0;
desRect.w = sourceRect.w;
desRect.h = sourceRect.h;

Set background màu đen cho cửa sổ sử dụng hàm:

SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

Với tham số thứ nhất chính là đối tượng renderer, 3 tham số tiếp theo lần lượt là các giá trị màu r, g, b, a.

Trong main loop tôi tiến hành vẽ texture lên cửa sổ

//main loop
while (isRunning)
{
	SDL_RenderClear(renderer);
	//main event
	while (SDL_PollEvent(&mainEvent))
	{
		switch (mainEvent.type)
		{
			//User - requested quit
			case SDL_QUIT:
			{
				isRunning = false;
				break;
			}
			default:
			{
				break;
			}
		}
	}

	SDL_RenderCopy(renderer, texture, &sourceRect, &desRect);
	SDL_RenderPresent(renderer);
}
  • Dòng 4: Xóa màn hình sau mỗi frame với màu của background được set với ở SDL_SetRenderDrawColor.
  • Dòng 23: Đây là mà chúng ta sử dụng để render texture với các tham số là:
    •  Tham số thứ nhất: đối tượng mà chúng ta sử dụng để render.
    • Tham số thứ hai: đối tượng texture mà ta muốn render.
    • Tham số thứ ba: một phần nào đó của texture mà ta muốn render. Nếu để NULL nó sẽ render toàn bộ texture.
    • Tham số thứ tư: hình chữ nhật xác đinh tọa độ mà texture muốn vẽ trên cửa sổ. Nếu chiều rộng và chiều cao lớn hơn hoặc nhỏ hơn texture muốn vẽ thì texture sẽ bị scale theo hình nhật này. Nếu để NULL texture sẽ được vẽ full màn hình.
  • Dòng 24: Cập nhập, vẽ lên cửa sổ.

Kết quả sau khi chạy chương trình

ss_1

Bây giời, tôi thay đổi các thông số của sourceRect desSource để có thể vẽ được 1/4 hình ảnh ở vị trí x= 200, y = 200 trên màn hình:

sourceRect.x = 0;
sourceRect.y = 0;
sourceRect.w = sourceRect.w / 2;
sourceRect.h = sourceRect.h / 2;

desRect.x = 200;
desRect.y = 200;
desRect.w = sourceRect.w;
desRect.h = sourceRect.h;

Kết quả sau khi chạy lại chương trình

 

Source code toàn bộ chương trình

#include <stdio.h>
#include <SDL.h>

#undef main
int main()
{

	SDL_Window* window = NULL;
	SDL_Renderer* renderer = NULL;
	SDL_Surface* tempSurface = NULL;
	SDL_Texture* texture = NULL;
	SDL_Event mainEvent;
	SDL_Rect sourceRect;
	SDL_Rect desRect;
	bool isRunning = true;

	//initializes  the subsystems
	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
	{
		printf("Unable to initialize SDL %s\n", SDL_GetError());
		return -1;
	}

	//Create window
	window = SDL_CreateWindow("Stdio.vn - SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, SDL_WINDOW_SHOWN);
	if (window == NULL)
	{
		printf("Could not create window %s", SDL_GetError());
		return -1;
	}


	//create a renderer
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
	if (renderer == NULL)
	{
		printf("Could not create render %s", SDL_GetError());
		return -1;
	}

	//create a tempSurface
	tempSurface = SDL_LoadBMP("texture_demo.bmp");
	//create a texutre from surface
	texture = SDL_CreateTextureFromSurface(renderer, tempSurface);
	//free surface
	SDL_FreeSurface(tempSurface);


	SDL_QueryTexture(texture, NULL, NULL, &sourceRect.w, &sourceRect.h);

	sourceRect.x = 0;
	sourceRect.y = 0;
	sourceRect.w = sourceRect.w / 2;
	sourceRect.h = sourceRect.h / 2;

	desRect.x = 200;
	desRect.y = 200;
	desRect.w = sourceRect.w;
	desRect.h = sourceRect.h;

	//set background color
	SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);

	//main loop
	while (isRunning)
	{
		// clear the window to black
		SDL_RenderClear(renderer);
		//main event
		while (SDL_PollEvent(&mainEvent))
		{
			switch (mainEvent.type)
			{
				//User - requested quit
				case SDL_QUIT:
				{
					isRunning = false;
					break;
				}
				default:
				{
					break;
				}
			}
		}

		// copy a portion of the texture to the current rendering target.
		SDL_RenderCopy(renderer, texture, &sourceRect, NULL);
		//draw to the screen
		SDL_RenderPresent(renderer);
	}

	//Destroy a window.
	SDL_DestroyWindow(window);

	//Destroy a renderer
	SDL_DestroyRenderer(renderer);

	//cleans up all initialized subsystems
	SDL_Quit();
	return 0;
}

Download demo

Stdio_SDL_LoadTexure_VS2013.zip

THẢO LUẬN
ĐÓNG