1. 程式人生 > >軟體渲染第一步,利用SDL搭建軟體渲染

軟體渲染第一步,利用SDL搭建軟體渲染

偶然間突然對計算機圖形學有了興趣,最後找到了《3D遊戲程式設計大師》,試著照著書上所寫的一步步實現軟體渲染演算法

但是這本書的年代比較久遠了,使用的是早已經淘汰了的DirectDraw,於是軟體渲染演算法的學習道路上有了障礙。這本書是從零開始實現軟體渲染演算法,最最基礎的功能有兩個:一是鎖定視訊記憶體並直接在視訊記憶體中寫入資料,實現繪製一個指定位置,指定顏色的點的功能;二是將點陣圖複製到表面上,其他的較為高階的二維渲染演算法,如畫線演算法,多邊形光柵化等等均基於這兩個功能,而三維的渲染演算法則又基於二維的渲染演算法,因此,只要實現前面所述的最基本的兩個功能,就能夠一步步的照著書中所寫搭建軟體渲染引擎。

接下來就介紹一下如何利用SDL2.0實現第一個繪製點的功能,程式碼如下,共有三個檔案:T3DLIB1.h, T3DLIB1.cpp,main.cpp

每個檔案的程式碼如下:

//T3DLIB1.h

#ifndef _T3DLIB1_H
#define _T3DLIB1_H
#include <Windows.h>
#include <SDL\SDL.h>
extern HWND g_hWnd;
extern HINSTANCE g_hInstance;
extern SDL_Window* g_pSDLWindow;
extern SDL_Surface* g_pScreenSurface;
extern SDL_Surface* g_pBackSurface;
extern int screen_width;
extern int screen_height;
extern int screen_bpp;
int SD_Init();
int SD_ClearBackSurface( UINT color );
int SD_Flip();
#endif

//T3DLIB1.cpp

#include "T3DLIB1.h"
#include <Windows.h>
#include <SDL\SDL.h>
HWND g_hWnd = NULL;
HINSTANCE g_hInstance = NULL;
SDL_Window* g_pSDLWindow = NULL;
SDL_Surface* g_pScreenSurface = NULL;
SDL_Surface* g_pBackSurface = NULL;
int screen_width = 0;
int screen_height = 0;
int screen_bpp = 32;
int SD_Init()
{
SDL_Init( SDL_INIT_VIDEO );
g_pSDLWindow = SDL_CreateWindowFrom( g_hWnd );
if ( g_pSDLWindow == NULL )
{
MessageBox( NULL, L"建立SDL視窗失敗!", L"錯誤!", MB_ICONERROR );
return 0;
}
g_pScreenSurface = SDL_GetWindowSurface( g_pSDLWindow );
g_pBackSurface = SDL_CreateRGBSurface( 0, screen_width, screen_height, 32, 0, 0, 0, 0 );
return 1;
}
int SD_ClearBackSurface( UINT color )
{
SDL_FillRect( g_pBackSurface, NULL, color );
return 1;
}
int SD_Flip()
{
SDL_BlitSurface( g_pBackSurface, NULL, g_pScreenSurface, NULL );
SDL_UpdateWindowSurface( g_pSDLWindow );
return 1;
}

// main.cpp

#include <Windows.h>
#include "T3DLIB1.h"
TCHAR szAppName[] = L"T3DLIB";
TCHAR szWndName[] = L"DrawPixel";
HRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
int GameInit();
int GameMain();
int GameShutdown();
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE , PSTR lpCmdLine, int nCmdShow )
{
WNDCLASS wndClass;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = ( HBRUSH ) GetStockObject( WHITE_BRUSH );
wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );
wndClass.hIcon = LoadIcon( NULL, IDI_APPLICATION );
wndClass.hInstance = hInstance;
g_hInstance = hInstance;
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = szAppName;
wndClass.lpszMenuName = NULL;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
if ( !RegisterClass( &wndClass ) )
{
MessageBox( NULL, L"註冊視窗類失敗", L"錯誤!", MB_ICONERROR );
}
g_hWnd = CreateWindow( szAppName, szWndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 512, 512, NULL, NULL, hInstance, 0 );
if ( !g_hWnd )
{
MessageBox( NULL, L"建立視窗失敗!", L"錯誤!", MB_ICONERROR );
}
ShowWindow( g_hWnd, nCmdShow );
UpdateWindow( g_hWnd );
MSG msg;
GameInit();
while ( 1 )
{
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if ( msg.message == WM_QUIT )
break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
GameMain();
}
return 0;
}
HRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
static HDC hdc;
static PAINTSTRUCT ps;
switch ( uMsg )
{
case WM_SIZE:
hdc = BeginPaint( hWnd, &ps );
RECT rect;
GetClientRect( hWnd, &rect );
screen_width = rect.right - rect.left;
screen_height = rect.bottom - rect.top;
EndPaint( hWnd, &ps );
return 0;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
int GameInit()
{
SD_Init();
return 1;
}
int GameMain()
{
SD_ClearBackSurface( 0 );
SDL_LockSurface( g_pBackSurface );
int lpitch = ( g_pBackSurface->pitch >> 2 );
UINT* video_buffer = ( UINT* ) g_pBackSurface->pixels;
for ( int i = 0; i < 1000; i++ )
{
int x = rand() % screen_width;
int y = rand() % screen_height;
video_buffer[ x + y * lpitch ] = 0x00ff0000;
}
SDL_UnlockSurface( g_pBackSurface );
SD_Flip();
for ( int i = 0; i < 1000; i++ )
{


}
return 1;
}
int GameShutdown()
{
return 1;
}

程式碼量很小,就不寫註釋了

最後達到的效果如圖:


有了這個就可以一步步照著書往下實現軟體渲染引擎了