
Beginning DirectX9 Dịch bởi TransTeam diễn đàn Gamedev.VN
40
Sau đây là một ví dụ đơn giản gọi tới hàm D3DLoadSurfaceFromFile, nó thực hiện tải
ảnh bitmap từ tệp tin test.bmp vào trong vùng đệm offscreen surface. Chú ý là bạn phải
tạo đối tượng surface lưu trữ bằng hàm CreateSurfaceFromFile trước khi gọi tới hàm này.
IDirect3DSurface9* surface;
hResult = D3DXLoadSurfaceFromFile( surface,
NULL,
NULL,
“test.bmp”,
NULL,
D3DX_DEFAULT,
0,
NULL );
if ( FAILED( hResult ) )
return NULL;
Sau lời gọi trên đây, dữ liệu toàn bộ ảnh bitmap trong tệp tin test.bmp sẽ được tải vào bộ
nhớ và sẵn sàng để bạn sử dụng.
Sử dụng DirectX để thể hiện một hình ảnh
Chúng ta đã học cách tạo một surface cũng như làm thế nào để tải một ảnh bitmap vào
trong nó, bây giờ là lúc chúng ta sẽ thể hiện nó. Để làm được điều này, bạn phải tạo một
số thay đổi trong hàm Render mà chúng ta đã tạo trước đó
Trong phần trước, chúng ta đã xây dựng hàm Render như đoạn mã minh hoạ dưới đây:
/*********************************************************************
* Render(void)
*********************************************************************/
void Render(void)
{
// Kiểm tra xem đối tượng Direct3D device đã thực sự được khởi tạo hay chưa.
if( NULL == pd3dDevice )
return;
// Xoá bộ đệm màn hình (back buffer) bằng màu xanh nước biển
pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Thể hiện hình ảnh từ dữ liệu trên bộ nhớ đệm màn hình
pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
Để hiển thị ảnh bitmap đó lên màn hình, bạn cần phải sử dụng hàm StretchRect, hàm này
sẽ thực hiện việc sao chép và kéo dãn, thay đổi tỷ lệ hình ảnh nếu 2 vùng chữ nhật lưu trữ
ảnh gốc và ảnh đích có kích thước khác nhau.
Hàm StretchRect này được định nghĩa như sau:
HRESULT StretchRect(
IDirect3DSurface9 *pSourceSurface,
CONST RECT *pSourceRect,
IDirect3DSurface9 *pDestSurface,
CONST RECT *pDestRect,
D3DTEXTUREFILTERTYPE Filter
);
Các tham số đầu vào của hàm StretchRect này bao gồm:
pSourceSurface. Con trỏ đối tượng surface quản lý các ảnh bitmap được tải vào.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com

Beginning DirectX9 Dịch bởi TransTeam diễn đàn Gamedev.VN
41
pSourceRect. Con trỏ kiểu RECT chứa dữ liệu vùng được sao chép. Néu tham số
này là NULL, toàn bộ dữ liệu surface gốc sẽ được sao chép.
pDestSurface. Con trỏ chứa đối tượng surface đích. Trong hầu hết các trường hợp,
nó là con trỏ của bộ đệm phụ back buffer.
pDestRect. Con trỏ kiểu RECT chứa dữ liệu vùng thể hiện đối tượng được sao
chép lên surface đích. Tham số này có thể là NULL nếu bạn kô muốn xác lập vùng
kết xuất.
Filter. Kiểu lọc sử dụng trong quá trình sao chép. Bạn có thể xác lập giá trị này là
D3DTEXF_NONE nếu không muốn xác lập kiểu lọc.
Có lẽ bạn sẽ tự hỏi làm thế nào đế có thể lấy được con trở chứa dữ liệu của bộ đệm back
buffer surface. Hàm để thực hiện chức năng này có tên là GetBackBuffer, cấu trúc của nó
có dạng như sau:
GetBackBuffer( 0, // giá trị thể hiện kiểu cháo đổi
0, // chỉ số của bộ đệm
// 0 nếu chỉ có một bộ đệm được sử dụng
D3DBACKBUFFER_TYPE_MONO, // một đối số định kiểu
&backbuffer); // đối tượng trả về có kiểu IDirect3DSurface9
Kết hợp thêm các lời gọi tới hàm StretchRect và GetBackBuffer, hàm Render của chúng
ta lúc này sẽ có dạng tương tự dưới đây:
/*********************************************************************
* Render
*********************************************************************/
void Render(void)
{
// Con trỏ bộ đệm back buffer
IDirect3DSurface9* backbuffer = NULL;
// Kiểm tra đối tượng Direct3D device đã tồn tại
if( NULL == pd3dDevice )
return;
// Xoá toàn bộ bộ đệm về màu xanh nước biển
pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Lấy con trỏ bộ đệm back buffer
pd3dDevice->GetBackBuffer( 0,
0,
D3DBACKBUFFER_TYPE_MONO,
&backbuffer );
// Sao chép toàn bộ dữ liệu offscreen surface vào bộ đệm
pd3dDevice->StretchRect( srcSurface,
NULL,
backbuffer,
NULL,
D3DTEXF_NONE );
// Thể hiện hình ảnh từ bộ đệm lên màn hình
pd3dDevice->Present ( NULL, NULL, NULL, NULL );
}
Bạn có thể tìm thấy mã nguồn của ví dụ này trong thư mục chapter3\example1 trên CD-
ROM. Biên dịch và chạy ứng dụng, một cửa sổ chương trình sẽ xuất hiện có dạng sau:
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com

Beginning DirectX9 Dịch bởi TransTeam diễn đàn Gamedev.VN
42
Hình 3.2 Hiển thị ảnh nền cho cửa sổ ứng dụng
Xem xét lại hàm StretchRect
Trong phần trước, chúng ta đã sử dụng hàm StretchRect để sao chép toàn bộ ảnh
offscreen surface vào bộ đệm, nhưng đó không phải là toàn bộ chức năng hữu dụng nhất
của hàm này. StretchRect còn cho phép bạn sao cheo một hoặc nhiều khung hình nhỏ của
ảnh offscreen surface, nó cho phép một surface có thể tạo nền từ nhiều hình nhỏ hơn. Ví
dụ, một ảnh offscreen surface có thể chứa rất nhiều khung hình chuyển động nhỏ của một
nhân vật, hoặc các hình ảnh nhỏ để tạo nên một puzzle game. Hàm StretchRect có 2 tham
số - pSourceRect và pDesRect – dùng để xác định vùng dữ liệu sẽ copy từ đâu đến đâu.
Hình 3.3 sẽ minh hoạ việc sử dụng chức năng này.
Hình 3.3 Ảnh bên tay trái là ảnh gốc và hình chữ nhật miêu tả vùng
dữ liệu sẽ được sao chép. Ảnh bên phải mô tả vị trí và vùng
ảnh được sao chép lên bộ đệm.
Trong ví dụ tiếp theo chúng ta sẽ sử dụng chức năng này để thể hiện một thông điệp lên
màn hình từ dữ liệu ảnh gốc chứa toàn bộ các chữ trong bảng chữ cái. Hình 3.4 minh hoạ
ảnh dữ liệu gốc này, như bạn có thể thấy tất cả các chữ cái được lưu trong các vùng chữ
nhật có kích thước giống nhau. Việc xác lập lưu các chữ cái với cùng một kích cỡ sẽ giúp
chúng ta tiện lợi hơn rất nhiều trong quá trình xử lý và tìm tới chữ cái cần thiết một cách
nhanh nhất.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com

Beginning DirectX9 Dịch bởi TransTeam diễn đàn Gamedev.VN
43
Bởi vì chúng ta sẽ phải sao chép nhiều khung hình nên chúng ta sẽ phải gọi tới hàm
StretchRect nhiều lần. Để mọi thứ trở nên đơn giản, chúng ta sẽ đặt tất cả những lời gọi
đó vào trong một vòng lặp bên trong hàm Render.
/*********************************************************************
* Render
*********************************************************************/
void Render(void)
{
int letterWidth=48; // Thông số bề ngang mặc đinh của một ô chữ cái
int letterHeight=48; // chiều cao mặc định của một ô chữ cái
int destx = 48; // Toạ độ X của đểm trên cùng phía bên trái của chữ cái đầu tiên
int desty = 96; // Toạ độ Y của đểm trên cùng phía bên trái của chữ cái đầu tiên
// Biến chứa con trỏ bộ đệm
IDirect3DSurface9* backbuffer = NULL;
// Kiểm tra đối tượng Direct3D device
if( NULL == pd3dDevice )
return;
// Xoá bộ đệm bằng màu xanh nước biển
pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET,
D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );
// Lấy con trỏ của bộ đệm
pd3dDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO, &backbuffer);
// Xác lập biến chứa vị trí chữ cái đang được xem xét
int count=0;
// Thực hiện vòng lặp trên từng ký tự của chuỗi thông điệp đầu vào
for ( char *c = message; c != “ “; c++ )
{
RECT src; // Dữ liệu vùng chữ nhật gốc và kết xuất
RECT dest;
int srcY = ( ( ( *c - ‘A’ ) / 6 ) ) * letterHeight; // Tìm toạ độ vùng dữ liệu sao chép gốc
int srcX = ( ( ( *c - ‘A’ ) %7 ) * letterWidth );
src.top = srcY ;
src.left = srcX;
src.right = src.left + letterWidth;
src.bottom = src.top + letterHeight;
// Tìm toạ độ vùng dữ liệu sẽ được sao chép tới
dest.top = desty;
dest.left = destx + ( letterWidth * count );
dest.right = dest.left + letterWidth;
dest.bottom = dest.top + letterHeight;
// Tăng biến đếm lên 1
count++;
// sao chép dữ liệu vào bộ đệm
pd3dDevice->StretchRect( srcSurface, // Dữ liệu surface gốc
src, // Vùng dữ liệu muôn sao chép
backbuffer, // Dữ liệu được sao chép vào
dest, // vùng dữ liệu được sao chép
D3DTEXF_NONE); // kiểu bộ lọc sử dụng
}
// Thể hiện dữ liệu từ bộ đệm lên màn hình
pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
Kết quả của ví dụ trên là thể hiện dòng chữ “HELLO WORLD” và đem lại cho người
dùng cảm giác của một bức thư tống tiền :). Hình 3.5 minh hoạ kết quả kết xuất của
chương trình. Bạn có thể tìm mã nguồn đầy đủ trong thư mục chapter3\example2.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com

Beginning DirectX9 Dịch bởi TransTeam diễn đàn Gamedev.VN
44
Trước khi vòng lặp được thực hiện đọc từng chữ cái của thông điệp, nó phải được định
nghĩa trước ở bên ngoài hàm render có dạng như sau:
char *message = “HELLO WORLD”;
Trong mỗi bước nhảy của vòng lặp, chúng ta sẽ tiến hành lọc trên từng chữ cái một. Ví
dụ, trong lần lặp đầu tiên, chúng ta sẽ chỉ làm việc với chữ cái H trong từ “HELLO”.
Đoạn mã tiếp theo sẽ tính toán vùng chữ nhật gốc bao gồm toạ độ X và Y của đỉnh trên
cùng góc bên trái của hình.
int srcY = ( ( ( *c - ‘A’ ) / 6 ) ) * letterHeight;
int srcX = ( ( ( *c - ‘A’ ) %7 ) * letterWidth);
Sau khi chúng ta đã có toạ độ của điểm này, chúng ta sẽ biết được đoạ độ điểm dưới cùng
bên phải của hình chữ nhật chứa chữ cái đó thông qua chiều cao và chiều rộng của nó.
src.top = srcY ;
src.left = srcX;
src.right = src.left + letterWidth;
src.bottom = src.top + letterHeight;
Tiếp đến chúng ta sẽ phải xác định vị trí mà chữ cái sẽ được đặt trên bộ đệm.
dest.top = desty;
dest.left = destx + ( letterWidth * count );
dest.right = dest.left + letterWidth;
dest.bottom = dest.top + letterHeight;
Chúng ta đã xác lập biến cout dùng để kiểm tra xem bao nhiêu chữ cái đã được vẽ trên
màn hình. Thông qua biến count này, chúng ta sẽ tính toán được toạ độ điểm của các chữ
cái cần chèn.
Hình 3.5 Hình minh hoạ sử dụng ảnh bitmap các
chữ cái để thể hiện chuỗi, Hello world.
Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com