diff --git a/premake5.lua b/premake5.lua index 591ab10..1074856 100755 --- a/premake5.lua +++ b/premake5.lua @@ -1,3 +1,6 @@ +GLEWdir = "C:/Users/aap/src/glew-2.1.0" +GLFW64dir = "C:/Users/aap/src/glfw-3.2.1.bin.WIN64" + workspace "librw" location "build" language "C++" @@ -9,8 +12,8 @@ workspace "librw" "win-amd64-null", "win-amd64-gl3", "win-amd64-d3d9" } filter { "system:linux" } platforms { "linux-x86-null", "linux-x86-gl3", - "linux-amd64-null", "linux-amd64-gl3" } - -- TODO: ps2 + "linux-amd64-null", "linux-amd64-gl3", + "ps2" } filter {} filter "configurations:Debug" @@ -28,8 +31,12 @@ workspace "librw" defines { "RW_GL3" } filter { "platforms:*d3d9" } defines { "RW_D3D9" } - filter { "platforms:*ps2" } + filter { "platforms:ps2" } defines { "RW_PS2" } + toolset "gcc" + gccprefix 'ee-' + buildoptions { "-nostdlib", "-fno-common" } + includedirs { "$(PS2SDK)/ee/include", "$(PS2SDK)/common/include" } filter { "platforms:*amd64*" } architecture "x86_64" @@ -41,8 +48,13 @@ workspace "librw" filter { "platforms:linux*" } system "linux" + filter { "platforms:win*gl3" } + defines { "GLEW_STATIC" } + includedirs { path.join(GLEWdir, "include") } + includedirs { path.join(GLFW64dir, "include") } + filter "action:vs*" - buildoptions { "/wd4996" } + buildoptions { "/wd4996", "/wd4244" } filter {} @@ -63,3 +75,83 @@ project "dumprwtree" includedirs { "." } libdirs { Libdir } links { "librw" } + +function findlibs() + filter { "platforms:linux*gl3" } + links { "GL", "GLEW", "glfw" } + filter { "platforms:win*gl3" } + defines { "GLEW_STATIC" } + filter { "platforms:win-amd64-gl3" } + libdirs { path.join(GLEWdir, "lib/Release/x64") } + libdirs { path.join(GLFW64dir, "lib-vc2015") } + filter { "platforms:win-x86-gl3" } + libdirs { path.join(GLEWdir, "lib/Release/Win32") } + filter { "platforms:win*gl3" } + links { "glew32s", "glfw3", "opengl32" } + filter { "platforms:*d3d9" } + links { "d3d9", "Xinput9_1_0" } + filter {} +end + +function skeleton() + files { "skeleton/*.cpp", "skeleton/*.h" } + includedirs { "skeleton" } +end + +function skeltool(dir) + targetdir (Bindir) + files { path.join("tools", dir, "*.cpp"), + path.join("tools", dir, "*.h") } + vpaths { + {["src"] = { path.join("tools", dir, "*") }}, + {["skeleton"] = { "skeleton/*" }}, + } + skeleton() + debugdir ( path.join("tools", dir) ) + includedirs { "." } + libdirs { Libdir } + links { "librw" } + findlibs() +end + +function vucode() + filter "files:**.dsm" + buildcommands { + 'cpp "%{file.relpath}" | dvp-as -o "%{cfg.objdir}/%{file.basename}.o"' + } + buildoutputs { '%{cfg.objdir}/%{file.basename}.o' } + filter {} +end + +project "clumpview" + kind "WindowedApp" + characterset ("MBCS") + skeltool("clumpview") + flags { "WinMain" } + removeplatforms { "*null" } + +project "ps2test" + kind "ConsoleApp" + targetdir (Bindir) + vucode() + removeplatforms { "*gl3", "*d3d9", "*null" } + targetextension '.elf' + includedirs { "." } + files { "tools/ps2test/*.cpp", + "tools/ps2test/vu/*.dsm", + "tools/ps2test/*.h" } + linkoptions '$(PS2SDK)/ee/startup/crt0.o' + linkoptions { '-mno-crt0', "-T$(PS2SDK)/ee/startup/linkfile" } + libdirs { "$(PS2SDK)/ee/lib" } + links { "librw" } + -- "c -lc" is a hack because we need -lc twice for some reason + links { "c -lc", "kernel", "mf" } + +project "ps2rastertest" + kind "ConsoleApp" + targetdir (Bindir) + removeplatforms { "*gl3", "*d3d9" } + files { "tools/ps2rastertest/*.cpp" } + includedirs { "." } + libdirs { Libdir } + links { "librw" } diff --git a/rw.h b/rw.h index 8638793..af7d6eb 100644 --- a/rw.h +++ b/rw.h @@ -15,9 +15,6 @@ #include "src/d3d/rwd3d.h" #include "src/d3d/rwd3d8.h" #include "src/d3d/rwd3d9.h" -#ifdef RW_OPENGL -#include -#endif #include "src/gl/rwwdgl.h" #include "src/gl/rwgl3.h" #include "src/gl/rwgl3shader.h" diff --git a/skeleton/glfw.cpp b/skeleton/glfw.cpp new file mode 100644 index 0000000..5690a04 --- /dev/null +++ b/skeleton/glfw.cpp @@ -0,0 +1,184 @@ +#include +#include +#include "skeleton.h" + +using namespace sk; +using namespace rw; + +#ifdef RW_OPENGL + +GLFWwindow *window; +int keymap[GLFW_KEY_LAST+1]; + +static void +initkeymap(void) +{ + int i; + for(i = 0; i < GLFW_KEY_LAST+1; i++) + keymap[i] = KEY_NULL; + keymap[GLFW_KEY_SPACE] = ' '; + keymap[GLFW_KEY_APOSTROPHE] = '\''; + keymap[GLFW_KEY_COMMA] = ','; + keymap[GLFW_KEY_MINUS] = '-'; + keymap[GLFW_KEY_PERIOD] = '.'; + keymap[GLFW_KEY_SLASH] = '/'; + keymap[GLFW_KEY_0] = '0'; + keymap[GLFW_KEY_1] = '1'; + keymap[GLFW_KEY_2] = '2'; + keymap[GLFW_KEY_3] = '3'; + keymap[GLFW_KEY_4] = '4'; + keymap[GLFW_KEY_5] = '5'; + keymap[GLFW_KEY_6] = '6'; + keymap[GLFW_KEY_7] = '7'; + keymap[GLFW_KEY_8] = '8'; + keymap[GLFW_KEY_9] = '9'; + keymap[GLFW_KEY_SEMICOLON] = ';'; + keymap[GLFW_KEY_EQUAL] = '='; + keymap[GLFW_KEY_A] = 'A'; + keymap[GLFW_KEY_B] = 'B'; + keymap[GLFW_KEY_C] = 'C'; + keymap[GLFW_KEY_D] = 'D'; + keymap[GLFW_KEY_E] = 'E'; + keymap[GLFW_KEY_F] = 'F'; + keymap[GLFW_KEY_G] = 'G'; + keymap[GLFW_KEY_H] = 'H'; + keymap[GLFW_KEY_I] = 'I'; + keymap[GLFW_KEY_J] = 'J'; + keymap[GLFW_KEY_K] = 'K'; + keymap[GLFW_KEY_L] = 'L'; + keymap[GLFW_KEY_M] = 'M'; + keymap[GLFW_KEY_N] = 'N'; + keymap[GLFW_KEY_O] = 'O'; + keymap[GLFW_KEY_P] = 'P'; + keymap[GLFW_KEY_Q] = 'Q'; + keymap[GLFW_KEY_R] = 'R'; + keymap[GLFW_KEY_S] = 'S'; + keymap[GLFW_KEY_T] = 'T'; + keymap[GLFW_KEY_U] = 'U'; + keymap[GLFW_KEY_V] = 'V'; + keymap[GLFW_KEY_W] = 'W'; + keymap[GLFW_KEY_X] = 'X'; + keymap[GLFW_KEY_Y] = 'Y'; + keymap[GLFW_KEY_Z] = 'Z'; + keymap[GLFW_KEY_LEFT_BRACKET] = '['; + keymap[GLFW_KEY_BACKSLASH] = '\\'; + keymap[GLFW_KEY_RIGHT_BRACKET] = ']'; + keymap[GLFW_KEY_GRAVE_ACCENT] = '`'; + keymap[GLFW_KEY_ESCAPE] = KEY_ESC; + keymap[GLFW_KEY_ENTER] = KEY_ENTER; + keymap[GLFW_KEY_TAB] = KEY_TAB; + keymap[GLFW_KEY_BACKSPACE] = KEY_BACKSP; + keymap[GLFW_KEY_INSERT] = KEY_INS; + keymap[GLFW_KEY_DELETE] = KEY_DEL; + keymap[GLFW_KEY_RIGHT] = KEY_RIGHT; + keymap[GLFW_KEY_LEFT] = KEY_LEFT; + keymap[GLFW_KEY_DOWN] = KEY_DOWN; + keymap[GLFW_KEY_UP] = KEY_UP; + keymap[GLFW_KEY_PAGE_UP] = KEY_PGUP; + keymap[GLFW_KEY_PAGE_DOWN] = KEY_PGDN; + keymap[GLFW_KEY_HOME] = KEY_HOME; + keymap[GLFW_KEY_END] = KEY_END; + keymap[GLFW_KEY_CAPS_LOCK] = KEY_CAPSLK; + keymap[GLFW_KEY_SCROLL_LOCK] = KEY_NULL; + keymap[GLFW_KEY_NUM_LOCK] = KEY_NULL; + keymap[GLFW_KEY_PRINT_SCREEN] = KEY_NULL; + keymap[GLFW_KEY_PAUSE] = KEY_NULL; + + keymap[GLFW_KEY_F1] = KEY_F1; + keymap[GLFW_KEY_F2] = KEY_F2; + keymap[GLFW_KEY_F3] = KEY_F3; + keymap[GLFW_KEY_F4] = KEY_F4; + keymap[GLFW_KEY_F5] = KEY_F5; + keymap[GLFW_KEY_F6] = KEY_F6; + keymap[GLFW_KEY_F7] = KEY_F7; + keymap[GLFW_KEY_F8] = KEY_F8; + keymap[GLFW_KEY_F9] = KEY_F9; + keymap[GLFW_KEY_F10] = KEY_F10; + keymap[GLFW_KEY_F11] = KEY_F11; + keymap[GLFW_KEY_F12] = KEY_F12; + keymap[GLFW_KEY_F13] = KEY_NULL; + keymap[GLFW_KEY_F14] = KEY_NULL; + keymap[GLFW_KEY_F15] = KEY_NULL; + keymap[GLFW_KEY_F16] = KEY_NULL; + keymap[GLFW_KEY_F17] = KEY_NULL; + keymap[GLFW_KEY_F18] = KEY_NULL; + keymap[GLFW_KEY_F19] = KEY_NULL; + keymap[GLFW_KEY_F20] = KEY_NULL; + keymap[GLFW_KEY_F21] = KEY_NULL; + keymap[GLFW_KEY_F22] = KEY_NULL; + keymap[GLFW_KEY_F23] = KEY_NULL; + keymap[GLFW_KEY_F24] = KEY_NULL; + keymap[GLFW_KEY_F25] = KEY_NULL; + keymap[GLFW_KEY_KP_0] = KEY_NULL; + keymap[GLFW_KEY_KP_1] = KEY_NULL; + keymap[GLFW_KEY_KP_2] = KEY_NULL; + keymap[GLFW_KEY_KP_3] = KEY_NULL; + keymap[GLFW_KEY_KP_4] = KEY_NULL; + keymap[GLFW_KEY_KP_5] = KEY_NULL; + keymap[GLFW_KEY_KP_6] = KEY_NULL; + keymap[GLFW_KEY_KP_7] = KEY_NULL; + keymap[GLFW_KEY_KP_8] = KEY_NULL; + keymap[GLFW_KEY_KP_9] = KEY_NULL; + keymap[GLFW_KEY_KP_DECIMAL] = KEY_NULL; + keymap[GLFW_KEY_KP_DIVIDE] = KEY_NULL; + keymap[GLFW_KEY_KP_MULTIPLY] = KEY_NULL; + keymap[GLFW_KEY_KP_SUBTRACT] = KEY_NULL; + keymap[GLFW_KEY_KP_ADD] = KEY_NULL; + keymap[GLFW_KEY_KP_ENTER] = KEY_NULL; + keymap[GLFW_KEY_KP_EQUAL] = KEY_NULL; + keymap[GLFW_KEY_LEFT_SHIFT] = KEY_LSHIFT; + keymap[GLFW_KEY_LEFT_CONTROL] = KEY_LCTRL; + keymap[GLFW_KEY_LEFT_ALT] = KEY_LALT; + keymap[GLFW_KEY_LEFT_SUPER] = KEY_NULL; + keymap[GLFW_KEY_RIGHT_SHIFT] = KEY_RSHIFT; + keymap[GLFW_KEY_RIGHT_CONTROL] = KEY_RCTRL; + keymap[GLFW_KEY_RIGHT_ALT] = KEY_RALT; + keymap[GLFW_KEY_RIGHT_SUPER] = KEY_NULL; + keymap[GLFW_KEY_MENU] = KEY_NULL; +} + +static void KeyUp(int key) { EventHandler(KEYUP, &key); } +static void KeyDown(int key) { EventHandler(KEYDOWN, &key); } + +static void +keypress(GLFWwindow *window, int key, int scancode, int action, int mods) +{ + if(key >= 0 && key <= GLFW_KEY_LAST){ + if(action == GLFW_RELEASE) KeyUp(keymap[key]); + else if(action == GLFW_PRESS) KeyDown(keymap[key]); + else if(action == GLFW_REPEAT) KeyDown(keymap[key]); + } +} + +int +main(int argc, char *argv[]) +{ + EventHandler(INITIALIZE, nil); + + engineStartParams.width = sk::globals.width; + engineStartParams.height = sk::globals.height; + engineStartParams.windowtitle = sk::globals.windowtitle; + engineStartParams.window = &window; + + if(EventHandler(RWINITIALIZE, nil) == EVENTERROR) + return 0; + + initkeymap(); + glfwSetKeyCallback(window, keypress); + + float lastTime = glfwGetTime()*1000; + while(!sk::globals.quit && !glfwWindowShouldClose(window)){ + float currTime = glfwGetTime()*1000; + float timeDelta = (currTime - lastTime)*0.001f; + glfwPollEvents(); + + EventHandler(IDLE, &timeDelta); + + lastTime = currTime; + } + + EventHandler(RWTERMINATE, nil); + + return 0; +} +#endif diff --git a/skeleton/skeleton.cpp b/skeleton/skeleton.cpp new file mode 100644 index 0000000..d0bdb55 --- /dev/null +++ b/skeleton/skeleton.cpp @@ -0,0 +1,57 @@ +#include +#include "skeleton.h" + +namespace sk { + +Globals globals; + +bool +InitRW(void) +{ + if(!rw::Engine::init()) + return false; + if(AppEventHandler(sk::PLUGINATTACH, nil) == EVENTERROR) + return false; + if(!rw::Engine::open()) + return false; + if(!rw::Engine::start(&engineStartParams)) + return false; + rw::engine->loadTextures = 1; + + rw::TexDictionary::setCurrent(rw::TexDictionary::create()); + rw::Image::setSearchPath("."); + return true; +} + +void +TerminateRW(void) +{ + // TODO: delete all tex dicts + rw::Engine::stop(); + rw::Engine::close(); + rw::Engine::term(); +} + +EventStatus +EventHandler(Event e, void *param) +{ + EventStatus s; + s = AppEventHandler(e, param); + if(e == QUIT){ + globals.quit = 1; + return EVENTPROCESSED; + } + if(s == EVENTNOTPROCESSED) + switch(e){ + case RWINITIALIZE: + return InitRW() ? EVENTPROCESSED : EVENTERROR; + case RWTERMINATE: + TerminateRW(); + return EVENTPROCESSED; + default: + break; + } + return s; +} + +} diff --git a/skeleton/skeleton.h b/skeleton/skeleton.h new file mode 100644 index 0000000..dc049d7 --- /dev/null +++ b/skeleton/skeleton.h @@ -0,0 +1,91 @@ +extern rw::EngineStartParams engineStartParams; + +namespace sk { + +using namespace rw; + +// same as RW skeleton +enum Key +{ + // ascii... + + KEY_ESC = 128, + + KEY_F1 = 129, + KEY_F2 = 130, + KEY_F3 = 131, + KEY_F4 = 132, + KEY_F5 = 133, + KEY_F6 = 134, + KEY_F7 = 135, + KEY_F8 = 136, + KEY_F9 = 137, + KEY_F10 = 138, + KEY_F11 = 139, + KEY_F12 = 140, + + KEY_INS = 141, + KEY_DEL = 142, + KEY_HOME = 143, + KEY_END = 144, + KEY_PGUP = 145, + KEY_PGDN = 146, + + KEY_UP = 147, + KEY_DOWN = 148, + KEY_LEFT = 149, + KEY_RIGHT = 150, + + // some stuff ommitted + + KEY_BACKSP = 168, + KEY_TAB = 169, + KEY_CAPSLK = 170, + KEY_ENTER = 171, + KEY_LSHIFT = 172, + KEY_RSHIFT = 173, + KEY_LCTRL = 174, + KEY_RCTRL = 175, + KEY_LALT = 176, + KEY_RALT = 177, + + KEY_NULL, // unused + KEY_NUMKEYS, +}; + +enum EventStatus +{ + EVENTERROR, + EVENTPROCESSED, + EVENTNOTPROCESSED +}; + +enum Event +{ + INITIALIZE, + RWINITIALIZE, + RWTERMINATE, + SELECTDEVICE, + PLUGINATTACH, + KEYDOWN, + KEYUP, + IDLE, + QUIT +}; + +struct Globals +{ + const char *windowtitle; + int32 width; + int32 height; + bool32 quit; +}; +extern Globals globals; + +bool InitRW(void); +void TerminateRW(void); +EventStatus EventHandler(Event e, void *param); + +} + +sk::EventStatus AppEventHandler(sk::Event e, void *param); diff --git a/skeleton/win.cpp b/skeleton/win.cpp new file mode 100644 index 0000000..b8cc034 --- /dev/null +++ b/skeleton/win.cpp @@ -0,0 +1,217 @@ +#include +#include +#include "skeleton.h" + +using namespace sk; +using namespace rw; + +#ifdef RW_D3D9 + +static int keymap[256]; +static void +initkeymap(void) +{ + int i; + for(i = 0; i < 256; i++) + keymap[i] = KEY_NULL; + keymap[VK_SPACE] = ' '; + keymap[VK_OEM_7] = '\''; + keymap[VK_OEM_COMMA] = ','; + keymap[VK_OEM_MINUS] = '-'; + keymap[VK_OEM_PERIOD] = '.'; + keymap[VK_OEM_2] = '/'; + for(i = '0'; i <= '9'; i++) + keymap[i] = i; + keymap[VK_OEM_1] = ';'; + keymap[VK_OEM_NEC_EQUAL] = '='; + for(i = 'A'; i <= 'Z'; i++) + keymap[i] = i; + keymap[VK_OEM_4] = '['; + keymap[VK_OEM_5] = '\\'; + keymap[VK_OEM_6] = ']'; + keymap[VK_OEM_3] = '`'; + keymap[VK_ESCAPE] = KEY_ESC; + keymap[VK_RETURN] = KEY_ENTER; + keymap[VK_TAB] = KEY_TAB; + keymap[VK_BACK] = KEY_BACKSP; + keymap[VK_INSERT] = KEY_INS; + keymap[VK_DELETE] = KEY_DEL; + keymap[VK_RIGHT] = KEY_RIGHT; + keymap[VK_LEFT] = KEY_LEFT; + keymap[VK_DOWN] = KEY_DOWN; + keymap[VK_UP] = KEY_UP; + keymap[VK_PRIOR] = KEY_PGUP; + keymap[VK_NEXT] = KEY_PGDN; + keymap[VK_HOME] = KEY_HOME; + keymap[VK_END] = KEY_END; + keymap[VK_MODECHANGE] = KEY_CAPSLK; + for(i = VK_F1; i <= VK_F24; i++) + keymap[i] = i-VK_F1+KEY_F1; + keymap[VK_LSHIFT] = KEY_LSHIFT; + keymap[VK_LCONTROL] = KEY_LCTRL; + keymap[VK_LMENU] = KEY_LALT; + keymap[VK_RSHIFT] = KEY_RSHIFT; + keymap[VK_RCONTROL] = KEY_RCTRL; + keymap[VK_RMENU] = KEY_RALT; +} +bool running; + +static void KeyUp(int key) { EventHandler(KEYUP, &key); } +static void KeyDown(int key) { EventHandler(KEYDOWN, &key); } + +LRESULT CALLBACK +WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg){ + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_SYSKEYDOWN: + case WM_KEYDOWN: + if(wParam == VK_MENU){ + if(GetKeyState(VK_LMENU) & 0x8000) KeyDown(keymap[VK_LMENU]); + if(GetKeyState(VK_RMENU) & 0x8000) KeyDown(keymap[VK_RMENU]); + }else if(wParam == VK_CONTROL){ + if(GetKeyState(VK_LCONTROL) & 0x8000) KeyDown(keymap[VK_LCONTROL]); + if(GetKeyState(VK_RCONTROL) & 0x8000) KeyDown(keymap[VK_RCONTROL]); + }else if(wParam == VK_SHIFT){ + if(GetKeyState(VK_LSHIFT) & 0x8000) KeyDown(keymap[VK_LSHIFT]); + if(GetKeyState(VK_RSHIFT) & 0x8000) KeyDown(keymap[VK_RSHIFT]); + }else + KeyDown(keymap[wParam]); + break; + + case WM_SYSKEYUP: + case WM_KEYUP: + if(wParam == VK_MENU){ + if((GetKeyState(VK_LMENU) & 0x8000) == 0) KeyUp(keymap[VK_LMENU]); + if((GetKeyState(VK_RMENU) & 0x8000) == 0) KeyUp(keymap[VK_RMENU]); + }else if(wParam == VK_CONTROL){ + if((GetKeyState(VK_LCONTROL) & 0x8000) == 0) KeyUp(keymap[VK_LCONTROL]); + if((GetKeyState(VK_RCONTROL) & 0x8000) == 0) KeyUp(keymap[VK_RCONTROL]); + }else if(wParam == VK_SHIFT){ + if((GetKeyState(VK_LSHIFT) & 0x8000) == 0) KeyUp(keymap[VK_LSHIFT]); + if((GetKeyState(VK_RSHIFT) & 0x8000) == 0) KeyUp(keymap[VK_RSHIFT]); + }else + KeyUp(keymap[wParam]); + break; + + case WM_CLOSE: + DestroyWindow(hwnd); + break; + + case WM_QUIT: + running = false; + break; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +HWND +MakeWindow(HINSTANCE instance, int width, int height, const char *title) +{ + WNDCLASS wc; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = instance; + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); + wc.lpszMenuName = 0; + wc.lpszClassName = "librwD3D9"; + if(!RegisterClass(&wc)){ + MessageBox(0, "RegisterClass() - FAILED", 0, 0); + return 0; + } + + HWND win; + win = CreateWindow("librwD3D9", title, + WS_BORDER | WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX, + 0, 0, width, height, 0, 0, instance, 0); + if(!win){ + MessageBox(0, "CreateWindow() - FAILED", 0, 0); + return 0; + } + ShowWindow(win, SW_SHOW); + UpdateWindow(win); + return win; +} + +void +pollEvents(void) +{ + MSG msg; + while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){ + if(msg.message == WM_QUIT){ + running = false; + break; + }else{ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } +} + +int WINAPI +WinMain(HINSTANCE instance, HINSTANCE, + PSTR cmdLine, int showCmd) +{ + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + + EventHandler(INITIALIZE, nil); + + HWND win = MakeWindow(instance, + sk::globals.width, sk::globals.height, + sk::globals.windowtitle); + if(win == 0){ + MessageBox(0, "MakeWindow() - FAILED", 0, 0); + return 0; + } + engineStartParams.window = win; + initkeymap(); + + if(EventHandler(RWINITIALIZE, nil) == EVENTERROR) + return 0; + + float lastTime = (float)GetTickCount(); + running = true; + while(pollEvents(), !globals.quit){ + float currTime = (float)GetTickCount(); + float timeDelta = (currTime - lastTime)*0.001f; + + EventHandler(IDLE, &timeDelta); + + lastTime = currTime; + } + + EventHandler(RWTERMINATE, nil); + + return 0; +} +#endif + +#ifdef RW_OPENGL +int main(int argc, char *argv[]); + +int WINAPI +WinMain(HINSTANCE instance, HINSTANCE, + PSTR cmdLine, int showCmd) +{ + char *argv[1] = { + "clumpview", + }; + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + + return main(1, argv); +} +#endif diff --git a/src/base.cpp b/src/base.cpp old mode 100644 new mode 100755 index 7ac5f11..bd263d8 --- a/src/base.cpp +++ b/src/base.cpp @@ -261,6 +261,7 @@ Matrix::translate(V3d *translation, CombineOp op) Matrix tmp; Matrix trans = identMat; trans.pos = *translation; + trans.flags &= ~IDENTITY; switch(op){ case COMBINEREPLACE: *this = trans; @@ -301,6 +302,26 @@ Matrix::scale(V3d *scale, CombineOp op) return this; } +Matrix* +Matrix::transform(Matrix *mat, CombineOp op) +{ + Matrix tmp; + switch(op){ + case COMBINEREPLACE: + *this = *mat; + break; + case COMBINEPRECONCAT: + mult(&tmp, mat, this); + *this = tmp; + break; + case COMBINEPOSTCONCAT: + mult(&tmp, this, mat); + *this = tmp; + break; + } + return this; +} + void Matrix::lookAt(const V3d &dir, const V3d &up) { @@ -457,28 +478,12 @@ Matrix::orthogonalError(void) float32 Matrix::identityError(void) { - V3d r { right.x-1.0f, right.y, right.z }; - V3d u { up.x, up.y-1.0f, up.z }; - V3d a { at.x, at.y, at.z-1.0f }; + V3d r = { right.x-1.0f, right.y, right.z }; + V3d u = { up.x, up.y-1.0f, up.z }; + V3d a = { at.x, at.y, at.z-1.0f }; return dot(r,r) + dot(u,u) + dot(a,a) + dot(pos,pos); } -#if 0 - -bool32 -Matrix::isIdentity(void) -{ - return matrixIsIdentity((float32*)this); -} - -void -Matrix::transpose(Matrix *m1, Matrix *m2) -{ - matrixTranspose((float32*)m1, (float32*)m2); -} - -#endif - #define PSEP_C '/' #define PSEP_S "/" #ifndef _WIN32 diff --git a/src/base.err b/src/base.err index 52df5b2..5e06a86 100644 --- a/src/base.err +++ b/src/base.err @@ -10,3 +10,11 @@ ECODE(ERR_VERSION, "Unsupported version %X") ECODE(ERR_PLATFORM, "Unsupported platform %d") +ECODE(ERR_ENGINEINIT, + "Engine could not be initialized") +ECODE(ERR_ENGINEOPEN, + "Engine could not be opened") +ECODE(ERR_ENGINESTART, + "Engine could not be started") +ECODE(ERR_INVRASTER, + "Invalid raster format") diff --git a/src/camera.cpp b/src/camera.cpp old mode 100644 new mode 100755 index 1477596..363c35f --- a/src/camera.cpp +++ b/src/camera.cpp @@ -12,18 +12,20 @@ namespace rw { +PluginList Camera::s_plglist = { sizeof(Camera), sizeof(Camera), nil, nil }; + void defaultBeginUpdateCB(Camera *cam) { engine->currentCamera = cam; Frame::syncDirty(); - engine->beginUpdate(cam); + engine->device.beginUpdate(cam); } void defaultEndUpdateCB(Camera *cam) { - engine->endUpdate(cam); + engine->device.endUpdate(cam); } static void @@ -182,7 +184,21 @@ cameraSync(ObjectWithFrame *obj) * and to clip space are handled by separate matrices there. * On these platforms the two matrices are built in the platform's * beginUpdate function. - * On the PS2 the 1/2 translation/shear is removed again on the VU1. + * On the PS2 the z- and w-rows are the same and the + * 1/2 translation/shear is removed again on the VU1 by + * subtracting the w-row/2 from the x- and y-rows. + * + * perspective: + * 1/2w 0 ox/2w -ox/2w + * 0 -1/2h -oy/2h oy/2h + * 0 0 1 0 + * 0 0 1 0 + * + * parallel: + * 1/2w 0 ox/2w -ox/2w + * 0 -1/2h -oy/2h oy/2h + * 0 0 1 0 + * 0 0 0 1 * * RW builds this matrix directly without using explicit * inversion and matrix multiplication. @@ -191,8 +207,8 @@ cameraSync(ObjectWithFrame *obj) Camera *cam = (Camera*)obj; Matrix inv, proj; Matrix::invertOrthonormal(&inv, cam->getFrame()->getLTM()); - float32 xscl = 2.0f/cam->viewWindow.x; - float32 yscl = 2.0f/cam->viewWindow.y; + float32 xscl = 1.0f/(2.0f*cam->viewWindow.x); + float32 yscl = 1.0f/(2.0f*cam->viewWindow.y); proj.flags = 0; proj.right.x = xscl; @@ -315,7 +331,14 @@ Camera::destroy(void) void Camera::clear(RGBA *col, uint32 mode) { - engine->clearCamera(this, col, mode); + engine->device.clearCamera(this, col, mode); +} + +void +Camera::showRaster(void) +{ + // TODO: camera raster + engine->device.showRaster(nil); } void @@ -323,8 +346,8 @@ calczShiftScale(Camera *cam) { float32 n = cam->nearPlane; float32 f = cam->farPlane; - float32 N = engine->zNear; - float32 F = engine->zFar; + float32 N = engine->device.zNear; + float32 F = engine->device.zFar; // RW does this N += (F - N)/10000.0f; F -= (F - N)/10000.0f; @@ -342,6 +365,8 @@ Camera::setNearPlane(float32 near) { this->nearPlane = near; calczShiftScale(this); + if(this->getFrame()) + this->getFrame()->updateObjects(); } void @@ -349,6 +374,32 @@ Camera::setFarPlane(float32 far) { this->farPlane = far; calczShiftScale(this); + if(this->getFrame()) + this->getFrame()->updateObjects(); +} + +void +Camera::setViewWindow(const V2d *window) +{ + this->viewWindow = *window; + if(this->getFrame()) + this->getFrame()->updateObjects(); +} + +void +Camera::setViewOffset(const V2d *offset) +{ + this->viewOffset = *offset; + if(this->getFrame()) + this->getFrame()->updateObjects(); +} + +void +Camera::setProjection(int32 proj) +{ + this->projection = proj; + if(this->getFrame()) + this->getFrame()->updateObjects(); } int32 @@ -424,10 +475,12 @@ Camera::streamGetSize(void) void Camera::setFOV(float32 fov, float32 ratio) { + V2d v; float32 a = tan(fov*3.14159f/360.0f); - this->viewWindow.x = a; - this->viewWindow.y = a/ratio; - this->viewOffset.set(0.0f, 0.0f); + v.set(a, a/ratio); + this->setViewWindow(&v); + v.set(0.0f, 0.0f); + this->setViewOffset(&v); } } diff --git a/src/clump.cpp b/src/clump.cpp index 2c33f79..258d737 100644 --- a/src/clump.cpp +++ b/src/clump.cpp @@ -13,6 +13,9 @@ namespace rw { +PluginList Clump::s_plglist = { sizeof(Clump), sizeof(Clump), nil, nil }; +PluginList Atomic::s_plglist = { sizeof(Atomic), sizeof(Atomic), nil, nil }; + // // Clump // @@ -523,7 +526,7 @@ Atomic::getPipeline(void) { return this->pipeline ? this->pipeline : - driver[platform]->defaultPipeline; + engine->driver[platform]->defaultPipeline; } void diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp index 8e8e6ae..49d7b5e 100644 --- a/src/d3d/d3d.cpp +++ b/src/d3d/d3d.cpp @@ -15,9 +15,7 @@ namespace d3d { bool32 isP8supported = 1; -#ifdef RW_D3D9 -IDirect3DDevice9 *device = nil; -#else +#ifndef RW_D3D9 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \ ((uint32)(uint8)(ch0) | ((uint32)(uint8)(ch1) << 8) | \ ((uint32)(uint8)(ch2) << 16) | ((uint32)(uint8)(ch3) << 24 )) @@ -186,7 +184,7 @@ createIndexBuffer(uint32 length) { #ifdef RW_D3D9 IDirect3DIndexBuffer9 *ibuf; - device->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ibuf, 0); + d3ddevice->CreateIndexBuffer(length, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &ibuf, 0); return ibuf; #else return new uint8[length]; @@ -227,7 +225,7 @@ createVertexBuffer(uint32 length, uint32 fvf, int32 pool) { #ifdef RW_D3D9 IDirect3DVertexBuffer9 *vbuf; - device->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY, fvf, (D3DPOOL)pool, &vbuf, 0); + d3ddevice->CreateVertexBuffer(length, D3DUSAGE_WRITEONLY, fvf, (D3DPOOL)pool, &vbuf, 0); return vbuf; #else (void)fvf; @@ -270,7 +268,7 @@ createTexture(int32 width, int32 height, int32 numlevels, uint32 format) { #ifdef RW_D3D9 IDirect3DTexture9 *tex; - device->CreateTexture(width, height, numlevels, 0, + d3ddevice->CreateTexture(width, height, numlevels, 0, (D3DFORMAT)format, D3DPOOL_MANAGED, &tex, nil); return tex; #else diff --git a/src/d3d/d3d8.cpp b/src/d3d/d3d8.cpp index cccf81f..454ff90 100644 --- a/src/d3d/d3d8.cpp +++ b/src/d3d/d3d8.cpp @@ -23,15 +23,15 @@ using namespace d3d; void* driverOpen(void *o, int32, int32) { - driver[PLATFORM_D3D8]->defaultPipeline = makeDefaultPipeline(); + engine->driver[PLATFORM_D3D8]->defaultPipeline = makeDefaultPipeline(); - driver[PLATFORM_D3D8]->rasterNativeOffset = nativeRasterOffset; - driver[PLATFORM_D3D8]->rasterCreate = rasterCreate; - driver[PLATFORM_D3D8]->rasterLock = rasterLock; - driver[PLATFORM_D3D8]->rasterUnlock = rasterUnlock; - driver[PLATFORM_D3D8]->rasterNumLevels = rasterNumLevels; - driver[PLATFORM_D3D8]->rasterFromImage = rasterFromImage; - driver[PLATFORM_D3D8]->rasterToImage = rasterToImage; + engine->driver[PLATFORM_D3D8]->rasterNativeOffset = nativeRasterOffset; + engine->driver[PLATFORM_D3D8]->rasterCreate = rasterCreate; + engine->driver[PLATFORM_D3D8]->rasterLock = rasterLock; + engine->driver[PLATFORM_D3D8]->rasterUnlock = rasterUnlock; + engine->driver[PLATFORM_D3D8]->rasterNumLevels = rasterNumLevels; + engine->driver[PLATFORM_D3D8]->rasterFromImage = rasterFromImage; + engine->driver[PLATFORM_D3D8]->rasterToImage = rasterToImage; return o; } @@ -102,7 +102,7 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) Geometry *geometry = (Geometry*)object; uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, nil)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); @@ -359,26 +359,26 @@ defaultInstanceCB(Geometry *geo, InstanceData *inst) uint8 *dst = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK); instV3d(VERT_FLOAT3, dst, - &geo->morphTargets[0].vertices[3*inst->minVert], + &geo->morphTargets[0].vertices[inst->minVert], inst->numVertices, inst->stride); dst += 12; if(geo->flags & Geometry::NORMALS){ instV3d(VERT_FLOAT3, dst, - &geo->morphTargets[0].normals[3*inst->minVert], + &geo->morphTargets[0].normals[inst->minVert], inst->numVertices, inst->stride); dst += 12; } inst->vertexAlpha = 0; if(geo->flags & Geometry::PRELIT){ - inst->vertexAlpha = instColor(VERT_ARGB, dst, &geo->colors[4*inst->minVert], + inst->vertexAlpha = instColor(VERT_ARGB, dst, &geo->colors[inst->minVert], inst->numVertices, inst->stride); dst += 4; } for(int32 i = 0; i < geo->numTexCoordSets; i++){ - instTexCoords(VERT_FLOAT2, dst, &geo->texCoords[i][2*inst->minVert], + instTexCoords(VERT_FLOAT2, dst, &geo->texCoords[i][inst->minVert], inst->numVertices, inst->stride); dst += 8; } @@ -390,26 +390,26 @@ defaultUninstanceCB(Geometry *geo, InstanceData *inst) { uint8 *src = lockVertices(inst->vertexBuffer, 0, 0, D3DLOCK_NOSYSLOCK); uninstV3d(VERT_FLOAT3, - &geo->morphTargets[0].vertices[3*inst->minVert], + &geo->morphTargets[0].vertices[inst->minVert], src, inst->numVertices, inst->stride); src += 12; if(geo->flags & Geometry::NORMALS){ uninstV3d(VERT_FLOAT3, - &geo->morphTargets[0].normals[3*inst->minVert], + &geo->morphTargets[0].normals[inst->minVert], src, inst->numVertices, inst->stride); src += 12; } inst->vertexAlpha = 0; if(geo->flags & Geometry::PRELIT){ - uninstColor(VERT_ARGB, &geo->colors[4*inst->minVert], src, + uninstColor(VERT_ARGB, &geo->colors[inst->minVert], src, inst->numVertices, inst->stride); src += 4; } for(int32 i = 0; i < geo->numTexCoordSets; i++){ - uninstTexCoords(VERT_FLOAT2, &geo->texCoords[i][2*inst->minVert], src, + uninstTexCoords(VERT_FLOAT2, &geo->texCoords[i][inst->minVert], src, inst->numVertices, inst->stride); src += 8; } @@ -481,7 +481,7 @@ readNativeTexture(Stream *stream) { uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, nil)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); diff --git a/src/d3d/d3d8render.cpp b/src/d3d/d3d8render.cpp index 8330529..c5aed73 100644 --- a/src/d3d/d3d8render.cpp +++ b/src/d3d/d3d8render.cpp @@ -7,6 +7,7 @@ #include "../rwplg.h" #include "../rwpipeline.h" #include "../rwobjects.h" +#include "../rwengine.h" #include "rwd3d.h" #include "rwd3d8.h" @@ -23,28 +24,31 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) { RawMatrix world; + d3d::lightingCB(); + Geometry *geo = atomic->geometry; + d3d::setRenderState(D3DRS_LIGHTING, !!(geo->flags & rw::Geometry::LIGHT)); + Frame *f = atomic->getFrame(); convMatrix(&world, f->getLTM()); - device->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&world); + d3ddevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&world); InstanceData *inst = header->inst; for(uint32 i = 0; i < header->numMeshes; i++){ d3d::setTexture(0, inst->material->texture); d3d::setMaterial(inst->material); - d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_ARGB(0xFF, 0x40, 0x40, 0x40)); d3d::setRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); d3d::setRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); if(geo->flags & Geometry::PRELIT) d3d::setRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1); - device->SetFVF(inst->vertexShader); - device->SetStreamSource(0, (IDirect3DVertexBuffer9*)inst->vertexBuffer, 0, inst->stride); - device->SetIndices((IDirect3DIndexBuffer9*)inst->indexBuffer); + d3ddevice->SetFVF(inst->vertexShader); + d3ddevice->SetStreamSource(0, (IDirect3DVertexBuffer9*)inst->vertexBuffer, 0, inst->stride); + d3ddevice->SetIndices((IDirect3DIndexBuffer9*)inst->indexBuffer); uint32 numPrim = inst->primType == D3DPT_TRIANGLESTRIP ? inst->numIndices-2 : inst->numIndices/3; d3d::flushCache(); - device->DrawIndexedPrimitive((D3DPRIMITIVETYPE)inst->primType, inst->baseIndex, - 0, inst->numVertices, 0, numPrim); + d3ddevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)inst->primType, inst->baseIndex, + 0, inst->numVertices, 0, numPrim); inst++; } } diff --git a/src/d3d/d3d9.cpp b/src/d3d/d3d9.cpp index 8ce74ee..a772b0c 100644 --- a/src/d3d/d3d9.cpp +++ b/src/d3d/d3d9.cpp @@ -31,15 +31,15 @@ static VertexElement _d3ddec_end = {0xFF,0,D3DDECLTYPE_UNUSED,0,0,0}; void* driverOpen(void *o, int32, int32) { - driver[PLATFORM_D3D9]->defaultPipeline = makeDefaultPipeline(); + engine->driver[PLATFORM_D3D9]->defaultPipeline = makeDefaultPipeline(); - driver[PLATFORM_D3D9]->rasterNativeOffset = nativeRasterOffset; - driver[PLATFORM_D3D9]->rasterCreate = rasterCreate; - driver[PLATFORM_D3D9]->rasterLock = rasterLock; - driver[PLATFORM_D3D9]->rasterUnlock = rasterUnlock; - driver[PLATFORM_D3D9]->rasterNumLevels = rasterNumLevels; - driver[PLATFORM_D3D9]->rasterFromImage = rasterFromImage; - driver[PLATFORM_D3D9]->rasterToImage = rasterToImage; + engine->driver[PLATFORM_D3D9]->rasterNativeOffset = nativeRasterOffset; + engine->driver[PLATFORM_D3D9]->rasterCreate = rasterCreate; + engine->driver[PLATFORM_D3D9]->rasterLock = rasterLock; + engine->driver[PLATFORM_D3D9]->rasterUnlock = rasterUnlock; + engine->driver[PLATFORM_D3D9]->rasterNumLevels = rasterNumLevels; + engine->driver[PLATFORM_D3D9]->rasterFromImage = rasterFromImage; + engine->driver[PLATFORM_D3D9]->rasterToImage = rasterToImage; return o; } @@ -64,7 +64,7 @@ createVertexDeclaration(VertexElement *elements) { #ifdef RW_D3D9 IDirect3DVertexDeclaration9 *decl = 0; - device->CreateVertexDeclaration((D3DVERTEXELEMENT9*)elements, &decl); + d3ddevice->CreateVertexDeclaration((D3DVERTEXELEMENT9*)elements, &decl); return decl; #else int n = 0; @@ -122,7 +122,7 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) Geometry *geometry = (Geometry*)object; uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, nil)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); @@ -592,7 +592,7 @@ readNativeTexture(Stream *stream) { uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, nil)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); diff --git a/src/d3d/d3d9render.cpp b/src/d3d/d3d9render.cpp index 44672a5..96dc440 100644 --- a/src/d3d/d3d9render.cpp +++ b/src/d3d/d3d9render.cpp @@ -7,6 +7,7 @@ #include "../rwplg.h" #include "../rwpipeline.h" #include "../rwobjects.h" +#include "../rwengine.h" #include "rwd3d.h" #include "rwd3d9.h" @@ -23,29 +24,32 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) { RawMatrix world; + d3d::lightingCB(); + Geometry *geo = atomic->geometry; + d3d::setRenderState(D3DRS_LIGHTING, !!(geo->flags & rw::Geometry::LIGHT)); + Frame *f = atomic->getFrame(); convMatrix(&world, f->getLTM()); - device->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&world); + d3ddevice->SetTransform(D3DTS_WORLD, (D3DMATRIX*)&world); - device->SetStreamSource(0, (IDirect3DVertexBuffer9*)header->vertexStream[0].vertexBuffer, - 0, header->vertexStream[0].stride); - device->SetIndices((IDirect3DIndexBuffer9*)header->indexBuffer); - device->SetVertexDeclaration((IDirect3DVertexDeclaration9*)header->vertexDeclaration); + d3ddevice->SetStreamSource(0, (IDirect3DVertexBuffer9*)header->vertexStream[0].vertexBuffer, + 0, header->vertexStream[0].stride); + d3ddevice->SetIndices((IDirect3DIndexBuffer9*)header->indexBuffer); + d3ddevice->SetVertexDeclaration((IDirect3DVertexDeclaration9*)header->vertexDeclaration); InstanceData *inst = header->inst; for(uint32 i = 0; i < header->numMeshes; i++){ d3d::setTexture(0, inst->material->texture); d3d::setMaterial(inst->material); - d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_ARGB(0xFF, 0x40, 0x40, 0x40)); d3d::setRenderState(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL); d3d::setRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL); if(geo->flags & Geometry::PRELIT) d3d::setRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_COLOR1); d3d::flushCache(); - device->DrawIndexedPrimitive((D3DPRIMITIVETYPE)header->primType, inst->baseIndex, - 0, inst->numVertices, - inst->startIndex, inst->numPrimitives); + d3ddevice->DrawIndexedPrimitive((D3DPRIMITIVETYPE)header->primType, inst->baseIndex, + 0, inst->numVertices, + inst->startIndex, inst->numPrimitives); inst++; } } diff --git a/src/d3d/d3ddevice.cpp b/src/d3d/d3ddevice.cpp new file mode 100755 index 0000000..d420914 --- /dev/null +++ b/src/d3d/d3ddevice.cpp @@ -0,0 +1,562 @@ +#include +#include +#include +#include + +#include "../rwbase.h" +#include "../rwplg.h" +#include "../rwerror.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "rwd3d.h" + +#define PLUGIN_ID 0 + +namespace rw { +namespace d3d { + +#ifdef RW_D3D9 + +// cached RW render states +static bool32 vertexAlpha; +static bool32 textureAlpha; +static uint32 srcblend, destblend; +static uint32 zwrite; +static uint32 ztest; +static uint32 fogenable; +static RGBA fogcolor; +static uint32 alphafunc; +static uint32 alpharef; + + +#define MAXNUMSTATES D3DRS_BLENDOPALPHA +#define MAXNUMSTAGES 8 +#define MAXNUMTEXSTATES D3DTSS_CONSTANT +#define MAXNUMSAMPLERSTATES D3DSAMP_DMAPOFFSET + +static int32 numDirtyStates; +static uint32 dirtyStates[MAXNUMSTATES]; +static struct { + uint32 value; + bool32 dirty; +} stateCache[MAXNUMSTATES]; +static uint32 d3dStates[MAXNUMSTATES]; + +static int32 numDirtyTextureStageStates; +static struct { + uint32 stage; + uint32 type; +} dirtyTextureStageStates[MAXNUMTEXSTATES*MAXNUMSTAGES]; +static struct { + uint32 value; + bool32 dirty; +} textureStageStateCache[MAXNUMSTATES][MAXNUMSTAGES]; +static uint32 d3dTextureStageStates[MAXNUMSTATES][MAXNUMSTAGES]; + +static uint32 d3dSamplerStates[MAXNUMSAMPLERSTATES][MAXNUMSTAGES]; + +// TODO: not only rasters, make a struct +static Raster *d3dRaster[MAXNUMSTAGES]; + +static D3DMATERIAL9 d3dmaterial; + +// D3D render state + +void +setRenderState(uint32 state, uint32 value) +{ + if(stateCache[state].value != value){ + stateCache[state].value = value; + if(!stateCache[state].dirty){ + stateCache[state].dirty = 1; + dirtyStates[numDirtyStates++] = state; + } + } +} + +void +setTextureStageState(uint32 stage, uint32 type, uint32 value) +{ + if(textureStageStateCache[type][stage].value != value){ + textureStageStateCache[type][stage].value = value; + if(!textureStageStateCache[type][stage].dirty){ + textureStageStateCache[type][stage].dirty = 1; + dirtyTextureStageStates[numDirtyTextureStageStates].stage = stage; + dirtyTextureStageStates[numDirtyTextureStageStates].type = type; + numDirtyTextureStageStates++; + } + } +} + +void +flushCache(void) +{ + uint32 s, t; + uint32 v; + for(int32 i = 0; i < numDirtyStates; i++){ + s = dirtyStates[i]; + v = stateCache[s].value; + stateCache[s].dirty = 0; + if(d3dStates[s] != v){ + d3ddevice->SetRenderState((D3DRENDERSTATETYPE)s, v); + d3dStates[s] = v; + } + } + numDirtyStates = 0; + for(int32 i = 0; i < numDirtyTextureStageStates; i++){ + s = dirtyTextureStageStates[i].stage; + t = dirtyTextureStageStates[i].type; + v = textureStageStateCache[t][s].value; + textureStageStateCache[t][s].dirty = 0; + if(d3dTextureStageStates[t][s] != v){ + d3ddevice->SetTextureStageState(s, (D3DTEXTURESTAGESTATETYPE)t, v); + d3dTextureStageStates[t][s] = v; + } + } + numDirtyTextureStageStates = 0; +} + +void +setSamplerState(uint32 stage, uint32 type, uint32 value) +{ + if(d3dSamplerStates[type][stage] != value){ + d3ddevice->SetSamplerState(stage, (D3DSAMPLERSTATETYPE)type, value); + d3dSamplerStates[type][stage] = value; + } +} + +// RW render state + +static void +setVertexAlpha(bool32 enable) +{ + if(vertexAlpha != enable){ + if(!textureAlpha){ + setRenderState(D3DRS_ALPHABLENDENABLE, enable); + setRenderState(D3DRS_ALPHATESTENABLE, enable); + } + vertexAlpha = enable; + } +} + +static uint32 blendMap[] = { + D3DBLEND_ZERO, + D3DBLEND_ONE, + D3DBLEND_SRCCOLOR, + D3DBLEND_INVSRCCOLOR, + D3DBLEND_SRCALPHA, + D3DBLEND_INVSRCALPHA, + D3DBLEND_DESTALPHA, + D3DBLEND_INVDESTALPHA, + D3DBLEND_DESTCOLOR, + D3DBLEND_INVDESTCOLOR, + D3DBLEND_SRCALPHASAT +}; + +uint32 alphafuncMap[] = { + D3DCMP_ALWAYS, + D3DCMP_GREATEREQUAL, + D3DCMP_LESS +}; + +static void +setRwRenderState(int32 state, uint32 value) +{ + uint32 bval = value ? TRUE : FALSE; + switch(state){ + case VERTEXALPHA: + setVertexAlpha(bval); + break; + case SRCBLEND: + if(srcblend != value){ + srcblend = value; + setRenderState(D3DRS_SRCBLEND, blendMap[value]); + } + break; + case DESTBLEND: + if(destblend != value){ + destblend = value; + setRenderState(D3DRS_DESTBLEND, blendMap[value]); + } + break; + case ZTESTENABLE: + if(ztest != bval){ + ztest = bval; + setRenderState(D3DRS_ZENABLE, ztest); + } + break; + case ZWRITEENABLE: + if(zwrite != bval){ + zwrite = bval; + setRenderState(D3DRS_ZWRITEENABLE, zwrite); + } + break; + case FOGENABLE: + if(fogenable != bval){ + fogenable = bval; + setRenderState(D3DRS_FOGENABLE, fogenable); + }; + break; + case FOGCOLOR:{ + RGBA c = *(RGBA*)&value; + if(!equal(fogcolor, c)){ + fogcolor = c; + setRenderState(D3DRS_FOGCOLOR, D3DCOLOR_RGBA(c.red, c.green, c.blue, c.alpha)); + }} break; + case ALPHATESTFUNC: + if(alphafunc != value){ + alphafunc = value; + setRenderState(D3DRS_ALPHAFUNC, alphafuncMap[alphafunc]); + } + break; + case ALPHATESTREF: + if(alpharef != value){ + alpharef = value; + setRenderState(D3DRS_ALPHAREF, alpharef); + } + break; + } +} + +static uint32 +getRwRenderState(int32 state) +{ + switch(state){ + case VERTEXALPHA: + return vertexAlpha; + case SRCBLEND: + return srcblend; + case DESTBLEND: + return destblend; + case ZTESTENABLE: + return ztest; + case ZWRITEENABLE: + return zwrite; + case FOGENABLE: + return fogenable; + case FOGCOLOR: + return *(uint32*)&fogcolor; + case ALPHATESTFUNC: + return alphafunc; + case ALPHATESTREF: + return alpharef; + } + return 0; +} + +void +setRasterStage(uint32 stage, Raster *raster) +{ + bool32 alpha; + D3dRaster *d3draster = nil; + if(raster != d3dRaster[stage]){ + d3dRaster[stage] = raster; + if(raster){ + d3draster = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset); + d3ddevice->SetTexture(stage, (IDirect3DTexture9*)d3draster->texture); + alpha = d3draster->hasAlpha; + }else{ + d3ddevice->SetTexture(stage, nil); + alpha = 0; + } + if(stage == 0){ + if(textureAlpha != alpha){ + textureAlpha = alpha; + if(!vertexAlpha){ + setRenderState(D3DRS_ALPHABLENDENABLE, alpha); + setRenderState(D3DRS_ALPHATESTENABLE, alpha); + } + } + } + } +} + +void +setTexture(uint32 stage, Texture *tex) +{ + static DWORD filternomip[] = { + 0, D3DTEXF_POINT, D3DTEXF_LINEAR, + D3DTEXF_POINT, D3DTEXF_LINEAR, + D3DTEXF_POINT, D3DTEXF_LINEAR + }; + static DWORD wrap[] = { + 0, D3DTADDRESS_WRAP, D3DTADDRESS_MIRROR, + D3DTADDRESS_CLAMP, D3DTADDRESS_BORDER + }; + if(tex == nil){ + setRasterStage(stage, nil); + return; + } + if(tex->raster){ + setSamplerState(stage, D3DSAMP_MAGFILTER, filternomip[tex->filterAddressing & 0xFF]); + setSamplerState(stage, D3DSAMP_MINFILTER, filternomip[tex->filterAddressing & 0xFF]); + setSamplerState(stage, D3DSAMP_ADDRESSU, wrap[(tex->filterAddressing >> 8) & 0xF]); + setSamplerState(stage, D3DSAMP_ADDRESSV, wrap[(tex->filterAddressing >> 12) & 0xF]); + } + setRasterStage(stage, tex->raster); +} + +void +setMaterial(Material *mat) +{ + D3DMATERIAL9 mat9; + D3DCOLORVALUE black = { 0, 0, 0, 0 }; + float ambmult = mat->surfaceProps.ambient/255.0f; + float diffmult = mat->surfaceProps.diffuse/255.0f; + mat9.Ambient.r = mat->color.red*ambmult; + mat9.Ambient.g = mat->color.green*ambmult; + mat9.Ambient.b = mat->color.blue*ambmult; + mat9.Ambient.a = mat->color.alpha*ambmult; + mat9.Diffuse.r = mat->color.red*diffmult; + mat9.Diffuse.g = mat->color.green*diffmult; + mat9.Diffuse.b = mat->color.blue*diffmult; + mat9.Diffuse.a = mat->color.alpha*diffmult; + mat9.Power = 0.0f; + mat9.Emissive = black; + mat9.Specular = black; + if(d3dmaterial.Diffuse.r != mat9.Diffuse.r || + d3dmaterial.Diffuse.g != mat9.Diffuse.g || + d3dmaterial.Diffuse.b != mat9.Diffuse.b || + d3dmaterial.Diffuse.a != mat9.Diffuse.a || + d3dmaterial.Ambient.r != mat9.Ambient.r || + d3dmaterial.Ambient.g != mat9.Ambient.g || + d3dmaterial.Ambient.b != mat9.Ambient.b || + d3dmaterial.Ambient.a != mat9.Ambient.a){ + d3ddevice->SetMaterial(&mat9); + d3dmaterial = mat9; + } +} + +static void +beginUpdate(Camera *cam) +{ + float view[16], proj[16]; + + // View Matrix + Matrix inv; + Matrix::invert(&inv, cam->getFrame()->getLTM()); + // Since we're looking into positive Z, + // flip X to ge a left handed view space. + view[0] = -inv.right.x; + view[1] = inv.right.y; + view[2] = inv.right.z; + view[3] = 0.0f; + view[4] = -inv.up.x; + view[5] = inv.up.y; + view[6] = inv.up.z; + view[7] = 0.0f; + view[8] = -inv.at.x; + view[9] = inv.at.y; + view[10] = inv.at.z; + view[11] = 0.0f; + view[12] = -inv.pos.x; + view[13] = inv.pos.y; + view[14] = inv.pos.z; + view[15] = 1.0f; + d3ddevice->SetTransform(D3DTS_VIEW, (D3DMATRIX*)view); + + // Projection Matrix + float32 invwx = 1.0f/cam->viewWindow.x; + float32 invwy = 1.0f/cam->viewWindow.y; + float32 invz = 1.0f/(cam->farPlane-cam->nearPlane); + + proj[0] = invwx; + proj[1] = 0.0f; + proj[2] = 0.0f; + proj[3] = 0.0f; + + proj[4] = 0.0f; + proj[5] = invwy; + proj[6] = 0.0f; + proj[7] = 0.0f; + + proj[8] = cam->viewOffset.x*invwx; + proj[9] = cam->viewOffset.y*invwy; + proj[12] = -proj[8]; + proj[13] = -proj[9]; + if(cam->projection == Camera::PERSPECTIVE){ + proj[10] = cam->farPlane*invz; + proj[11] = 1.0f; + + proj[15] = 0.0f; + }else{ + proj[10] = invz; + proj[11] = 0.0f; + + proj[15] = 1.0f; + } + proj[14] = -cam->nearPlane*proj[10]; + d3ddevice->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)proj); + + // TODO: figure out where this is really done + setRenderState(D3DRS_FOGSTART, *(uint32*)&cam->fogPlane); + setRenderState(D3DRS_FOGEND, *(uint32*)&cam->farPlane); + + // TODO: figure out when to call this + d3ddevice->BeginScene(); +} + +static void +endUpdate(Camera *cam) +{ + // TODO: figure out when to call this + d3ddevice->EndScene(); +} + +static void +clearCamera(Camera *cam, RGBA *col, uint32 mode) +{ + int flags = 0; + if(mode & Camera::CLEARIMAGE) + mode |= D3DCLEAR_TARGET; + if(mode & Camera::CLEARZ) + mode |= D3DCLEAR_ZBUFFER; + D3DCOLOR c = D3DCOLOR_RGBA(col->red, col->green, col->blue, col->alpha); + d3ddevice->Clear(0, 0, mode, c, 1.0f, 0); +} + +static void +showRaster(Raster *raster) +{ + // TODO: do this properly! + d3ddevice->Present(nil, nil, 0, nil); +} + +// taken from Frank Luna's d3d9 book +static int +startD3D(EngineStartParams *params) +{ + HWND win = params->window; + bool windowed = true; + + HRESULT hr = 0; + IDirect3D9 *d3d9 = 0; + d3d9 = Direct3DCreate9(D3D_SDK_VERSION); + if(!d3d9){ + RWERROR((ERR_GENERAL, "Direct3DCreate9() failed")); + return 0; + } + + D3DCAPS9 caps; + d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps); + int vp = 0; + if(caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) + vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; + else + vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; + + RECT rect; + GetClientRect(win, &rect); + int width = rect.right - rect.left; + int height = rect.bottom - rect.top; + + D3DPRESENT_PARAMETERS d3dpp; + d3dpp.BackBufferWidth = width; + d3dpp.BackBufferHeight = height; + d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = win; + d3dpp.Windowed = windowed; + d3dpp.EnableAutoDepthStencil = true; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.Flags = 0; + d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + IDirect3DDevice9 *dev; + hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, win, + vp, &d3dpp, &dev); + if(FAILED(hr)){ + // try again using a 16-bit depth buffer + d3dpp.AutoDepthStencilFormat = D3DFMT_D16; + + hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + win, vp, &d3dpp, &dev); + + if(FAILED(hr)){ + RWERROR((ERR_GENERAL, "CreateDevice() failed")); + d3d9->Release(); + return 0; + } + } + d3d9->Release(); + d3d::d3ddevice = dev; + return 1; +} + +static int +stopD3D(void) +{ + d3d::d3ddevice->Release(); + d3d::d3ddevice = nil; + return 1; +} + +static int +initD3D(void) +{ + // TODO: do some real stuff here + + d3ddevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); + alphafunc = ALPHAGREATEREQUAL; + d3ddevice->SetRenderState(D3DRS_ALPHAREF, 10); + alpharef = 10; + + d3ddevice->SetRenderState(D3DRS_FOGENABLE, FALSE); + fogenable = 0; + d3ddevice->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_LINEAR); + // TODO: more fog stuff + + d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + + d3ddevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); + d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + srcblend = BLENDSRCALPHA; + d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + destblend = BLENDINVSRCALPHA; + d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 0); + vertexAlpha = 0; + textureAlpha = 0; + + setTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); +// setTextureStageState(0, D3DTSS_CONSTANT, 0xFFFFFFFF); +// setTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); +// setTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_CONSTANT); +// setTextureStageState(0, D3DTSS_COLOROP, D3DTA_CONSTANT); + + return 1; +} + +static int +deviceSystem(DeviceReq req, void *arg0) +{ + switch(req){ + case DEVICESTART: + return startD3D((EngineStartParams*)arg0); + case DEVICEINIT: + return initD3D(); + case DEVICESTOP: + return stopD3D(); + } + return 1; +} + +Device renderdevice = { + 0.0f, 1.0f, + d3d::beginUpdate, + d3d::endUpdate, + d3d::clearCamera, + d3d::showRaster, + d3d::setRwRenderState, + d3d::getRwRenderState, + null::im2DRenderIndexedPrimitive, + d3d::deviceSystem, +}; + +#endif +} +} diff --git a/src/d3d/d3ddriver.cpp b/src/d3d/d3ddriver.cpp deleted file mode 100644 index 12cf481..0000000 --- a/src/d3d/d3ddriver.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include -#include -#include -#include - -#include "../rwbase.h" -#include "../rwplg.h" -#include "../rwpipeline.h" -#include "../rwobjects.h" -#include "../rwengine.h" -#include "rwd3d.h" - -namespace rw { -namespace d3d { - -#ifdef RW_D3D9 - -#define MAXNUMSTATES D3DRS_BLENDOPALPHA -#define MAXNUMSTAGES 8 -#define MAXNUMTEXSTATES D3DTSS_CONSTANT -#define MAXNUMSAMPLERSTATES D3DSAMP_DMAPOFFSET - -static int32 numDirtyStates; -static uint32 dirtyStates[MAXNUMSTATES]; -static struct { - uint32 value; - bool32 dirty; -} stateCache[MAXNUMSTATES]; -static uint32 d3dStates[MAXNUMSTATES]; - -static int32 numDirtyTextureStageStates; -static struct { - uint32 stage; - uint32 type; -} dirtyTextureStageStates[MAXNUMTEXSTATES*MAXNUMSTAGES]; -static struct { - uint32 value; - bool32 dirty; -} textureStageStateCache[MAXNUMSTATES][MAXNUMSTAGES]; -static uint32 d3dTextureStageStates[MAXNUMSTATES][MAXNUMSTAGES]; - -static uint32 d3dSamplerStates[MAXNUMSAMPLERSTATES][MAXNUMSTAGES]; - -static Raster *d3dRaster[MAXNUMSTAGES]; - -static D3DMATERIAL9 d3dmaterial; - -void -setRenderState(uint32 state, uint32 value) -{ - if(stateCache[state].value != value){ - stateCache[state].value = value; - if(!stateCache[state].dirty){ - stateCache[state].dirty = 1; - dirtyStates[numDirtyStates++] = state; - } - } -} - -void -setTextureStageState(uint32 stage, uint32 type, uint32 value) -{ - if(textureStageStateCache[type][stage].value != value){ - textureStageStateCache[type][stage].value = value; - if(!textureStageStateCache[type][stage].dirty){ - textureStageStateCache[type][stage].dirty = 1; - dirtyTextureStageStates[numDirtyTextureStageStates].stage = stage; - dirtyTextureStageStates[numDirtyTextureStageStates].type = type; - numDirtyTextureStageStates++; - } - } -} - -void -flushCache(void) -{ - uint32 s, t; - uint32 v; - for(int32 i = 0; i < numDirtyStates; i++){ - s = dirtyStates[i]; - v = stateCache[s].value; - stateCache[s].dirty = 0; - if(d3dStates[s] != v){ - device->SetRenderState((D3DRENDERSTATETYPE)s, v); - d3dStates[s] = v; - } - } - numDirtyStates = 0; - for(int32 i = 0; i < numDirtyTextureStageStates; i++){ - s = dirtyTextureStageStates[i].stage; - t = dirtyTextureStageStates[i].type; - v = textureStageStateCache[t][s].value; - textureStageStateCache[t][s].dirty = 0; - if(d3dTextureStageStates[t][s] != v){ - device->SetTextureStageState(s, (D3DTEXTURESTAGESTATETYPE)t, v); - d3dTextureStageStates[t][s] = v; - } - } - numDirtyTextureStageStates = 0; -} - -void -setSamplerState(uint32 stage, uint32 type, uint32 value) -{ - if(d3dSamplerStates[type][stage] != value){ - device->SetSamplerState(stage, (D3DSAMPLERSTATETYPE)type, value); - d3dSamplerStates[type][stage] = value; - } -} - -void -setRasterStage(uint32 stage, Raster *raster) -{ - D3dRaster *d3draster = nil; - if(raster != d3dRaster[stage]){ - d3dRaster[stage] = raster; - if(raster){ - d3draster = PLUGINOFFSET(D3dRaster, raster, nativeRasterOffset); - device->SetTexture(stage, (IDirect3DTexture9*)d3draster->texture); - }else - device->SetTexture(stage, nil); - } -} - -void -setTexture(uint32 stage, Texture *tex) -{ - static DWORD filternomip[] = { - 0, D3DTEXF_POINT, D3DTEXF_LINEAR, - D3DTEXF_POINT, D3DTEXF_LINEAR, - D3DTEXF_POINT, D3DTEXF_LINEAR - }; - static DWORD wrap[] = { - 0, D3DTADDRESS_WRAP, D3DTADDRESS_MIRROR, - D3DTADDRESS_CLAMP, D3DTADDRESS_BORDER - }; - if(tex == nil){ - setRasterStage(stage, nil); - return; - } - if(tex->raster){ - setSamplerState(stage, D3DSAMP_MAGFILTER, filternomip[tex->filterAddressing & 0xFF]); - setSamplerState(stage, D3DSAMP_MINFILTER, filternomip[tex->filterAddressing & 0xFF]); - setSamplerState(stage, D3DSAMP_ADDRESSU, wrap[(tex->filterAddressing >> 8) & 0xF]); - setSamplerState(stage, D3DSAMP_ADDRESSV, wrap[(tex->filterAddressing >> 12) & 0xF]); - } - setRasterStage(stage, tex->raster); -} - -void -setMaterial(Material *mat) -{ - D3DMATERIAL9 mat9; - D3DCOLORVALUE black = { 0, 0, 0, 0 }; - float ambmult = mat->surfaceProps.ambient/255.0f; - float diffmult = mat->surfaceProps.diffuse/255.0f; - mat9.Ambient.r = mat->color.red*ambmult; - mat9.Ambient.g = mat->color.green*ambmult; - mat9.Ambient.b = mat->color.blue*ambmult; - mat9.Ambient.a = mat->color.alpha*ambmult; - mat9.Diffuse.r = mat->color.red*diffmult; - mat9.Diffuse.g = mat->color.green*diffmult; - mat9.Diffuse.b = mat->color.blue*diffmult; - mat9.Diffuse.a = mat->color.alpha*diffmult; - mat9.Power = 0.0f; - mat9.Emissive = black; - mat9.Specular = black; - if(d3dmaterial.Diffuse.r != mat9.Diffuse.r || - d3dmaterial.Diffuse.g != mat9.Diffuse.g || - d3dmaterial.Diffuse.b != mat9.Diffuse.b || - d3dmaterial.Diffuse.a != mat9.Diffuse.a || - d3dmaterial.Ambient.r != mat9.Ambient.r || - d3dmaterial.Ambient.g != mat9.Ambient.g || - d3dmaterial.Ambient.b != mat9.Ambient.b || - d3dmaterial.Ambient.a != mat9.Ambient.a){ - device->SetMaterial(&mat9); - d3dmaterial = mat9; - } -} - -void -beginUpdate(Camera *cam) -{ - float view[16], proj[16]; - - // View Matrix - Matrix inv; - Matrix::invertOrthonormal(&inv, cam->getFrame()->getLTM()); - // Since we're looking into positive Z, - // flip X to ge a left handed view space. - view[0] = -inv.right.x; - view[1] = inv.right.y; - view[2] = inv.right.z; - view[3] = 0.0f; - view[4] = -inv.up.x; - view[5] = inv.up.y; - view[6] = inv.up.z; - view[7] = 0.0f; - view[8] = -inv.at.x; - view[9] = inv.at.y; - view[10] = inv.at.z; - view[11] = 0.0f; - view[12] = -inv.pos.x; - view[13] = inv.pos.y; - view[14] = inv.pos.z; - view[15] = 1.0f; - device->SetTransform(D3DTS_VIEW, (D3DMATRIX*)view); - - // Projection Matrix - float32 invwx = 1.0f/cam->viewWindow.x; - float32 invwy = 1.0f/cam->viewWindow.y; - float32 invz = 1.0f/(cam->farPlane-cam->nearPlane); - - proj[0] = invwx; - proj[1] = 0.0f; - proj[2] = 0.0f; - proj[3] = 0.0f; - - proj[4] = 0.0f; - proj[5] = invwy; - proj[6] = 0.0f; - proj[7] = 0.0f; - - proj[8] = cam->viewOffset.x*invwx; - proj[9] = cam->viewOffset.y*invwy; - proj[12] = -proj[8]; - proj[13] = -proj[9]; - if(cam->projection == Camera::PERSPECTIVE){ - proj[10] = cam->farPlane*invz; - proj[11] = 1.0f; - - proj[15] = 0.0f; - }else{ - proj[10] = invz; - proj[11] = 0.0f; - - proj[15] = 1.0f; - } - proj[14] = -cam->nearPlane*proj[10]; - device->SetTransform(D3DTS_PROJECTION, (D3DMATRIX*)proj); -} - -void -initializeRender(void) -{ - engine->beginUpdate = beginUpdate; -} - -#endif -} -} diff --git a/src/d3d/d3drender.cpp b/src/d3d/d3drender.cpp new file mode 100644 index 0000000..828b4ce --- /dev/null +++ b/src/d3d/d3drender.cpp @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include "../rwbase.h" +#include "../rwplg.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "rwd3d.h" + +namespace rw { +namespace d3d { + +#ifdef RW_D3D9 +IDirect3DDevice9 *d3ddevice = nil; + +#define MAX_LIGHTS 8 + +void +lightingCB(void) +{ + World *world; + RGBAf ambLight = { 0.0, 0.0, 0.0, 1.0 }; + RGBA amb; + D3DLIGHT9 light; + light.Type = D3DLIGHT_DIRECTIONAL; + //light.Diffuse = { 0.8f, 0.8f, 0.8f, 1.0f }; + light.Specular = { 0.0f, 0.0f, 0.0f, 0.0f }; + light.Ambient = { 0.0f, 0.0f, 0.0f, 0.0f }; + light.Position = { 0.0f, 0.0f, 0.0f }; + //light.Direction = { 0.0f, 0.0f, -1.0f }; + light.Range = 0.0f; + light.Falloff = 0.0f; + light.Attenuation0 = 0.0f; + light.Attenuation1 = 0.0f; + light.Attenuation2 = 0.0f; + light.Theta = 0.0f; + light.Phi = 0.0f; + int n = 0; + + world = (World*)engine->currentWorld; + // only unpositioned lights right now + FORLIST(lnk, world->directionalLights){ + Light *l = Light::fromWorld(lnk); + if(l->getType() == Light::DIRECTIONAL){ + if(n >= MAX_LIGHTS) + continue; + light.Diffuse = *(D3DCOLORVALUE*)&l->color; + light.Direction = *(D3DVECTOR*)&l->getFrame()->getLTM()->at; + d3ddevice->SetLight(n, &light); + d3ddevice->LightEnable(n, TRUE); + n++; + }else if(l->getType() == Light::AMBIENT){ + ambLight.red += l->color.red; + ambLight.green += l->color.green; + ambLight.blue += l->color.blue; + } + } + for(; n < MAX_LIGHTS; n++) + d3ddevice->LightEnable(n, FALSE); + convColor(&amb, &ambLight); + d3d::setRenderState(D3DRS_AMBIENT, D3DCOLOR_RGBA(amb.red, amb.green, amb.blue, amb.alpha)); +} + +#endif + +} +} diff --git a/src/d3d/rwd3d.h b/src/d3d/rwd3d.h index bc0014b..836d8d3 100644 --- a/src/d3d/rwd3d.h +++ b/src/d3d/rwd3d.h @@ -4,14 +4,23 @@ #endif namespace rw { -namespace d3d { -void initializeRender(void); +#ifdef RW_D3D9 +struct EngineStartParams +{ + HWND window; +}; +#endif + +namespace d3d { extern bool32 isP8supported; #ifdef RW_D3D9 -extern IDirect3DDevice9 *device; +extern IDirect3DDevice9 *d3ddevice; +extern Device renderdevice; + +void lightingCB(void); #else enum { D3DLOCK_NOSYSLOCK = 0, // ignored diff --git a/src/d3d/xbox.cpp b/src/d3d/xbox.cpp index 406c40f..5adb2c9 100644 --- a/src/d3d/xbox.cpp +++ b/src/d3d/xbox.cpp @@ -21,13 +21,13 @@ namespace xbox { void* driverOpen(void *o, int32, int32) { - driver[PLATFORM_XBOX]->defaultPipeline = makeDefaultPipeline(); + engine->driver[PLATFORM_XBOX]->defaultPipeline = makeDefaultPipeline(); - driver[PLATFORM_XBOX]->rasterNativeOffset = nativeRasterOffset; - driver[PLATFORM_XBOX]->rasterCreate = rasterCreate; - driver[PLATFORM_XBOX]->rasterLock = rasterLock; - driver[PLATFORM_XBOX]->rasterUnlock = rasterUnlock; - driver[PLATFORM_XBOX]->rasterNumLevels = rasterNumLevels; + engine->driver[PLATFORM_XBOX]->rasterNativeOffset = nativeRasterOffset; + engine->driver[PLATFORM_XBOX]->rasterCreate = rasterCreate; + engine->driver[PLATFORM_XBOX]->rasterLock = rasterLock; + engine->driver[PLATFORM_XBOX]->rasterUnlock = rasterUnlock; + engine->driver[PLATFORM_XBOX]->rasterNumLevels = rasterNumLevels; // TODO: from image return o; @@ -71,7 +71,7 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) uint32 vers; uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, &vers)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); @@ -622,7 +622,7 @@ readNativeTexture(Stream *stream) { uint32 vers, platform; if(!findChunk(stream, ID_STRUCT, nil, &vers)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); diff --git a/src/d3d/xboxplugins.cpp b/src/d3d/xboxplugins.cpp index 2561b8f..8dc6eca 100644 --- a/src/d3d/xboxplugins.cpp +++ b/src/d3d/xboxplugins.cpp @@ -35,7 +35,7 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset) Geometry *geometry = (Geometry*)object; uint32 vers, platform; if(!findChunk(stream, ID_STRUCT, nil, &vers)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); diff --git a/src/engine.cpp b/src/engine.cpp old mode 100644 new mode 100755 index 833277e..0b7b53a --- a/src/engine.cpp +++ b/src/engine.cpp @@ -3,6 +3,7 @@ #include #include "rwbase.h" +#include "rwerror.h" #include "rwplg.h" #include "rwpipeline.h" #include "rwobjects.h" @@ -15,22 +16,55 @@ #include "gl/rwgl3.h" #include "gl/rwwdgl.h" +#define PLUGIN_ID 0 + namespace rw { Engine *engine; -Driver *driver[NUM_PLATFORMS]; +PluginList Driver::s_plglist[NUM_PLATFORMS]; +Engine::State Engine::state = Dead; -void +// This function mainly registers engine plugins +// RW initializes memory related things here too and +// uses more plugins +// TODO: do this^ ? +bool32 Engine::init(void) { - engine = new Engine; - PluginList init = { sizeof(Driver), sizeof(Driver), nil, nil }; + if(engine || Engine::state != Dead){ + RWERROR((ERR_ENGINEINIT)); + return 0; + } + PluginList init = { sizeof(Driver), sizeof(Driver), nil, nil }; for(uint i = 0; i < NUM_PLATFORMS; i++) Driver::s_plglist[i] = init; - Frame::dirtyList.init(); + // Register plugins + // TODO: these are wrong + ps2::initializePlatform(); + xbox::initializePlatform(); + d3d8::initializePlatform(); + d3d9::initializePlatform(); + wdgl::initializePlatform(); + gl3::initializePlatform(); + Engine::state = Initialized; + return 1; +} + +// This is where RW allocates the engine and e.g. opens d3d +// TODO: this will take an argument with device specific data (HWND &c.) +bool32 +Engine::open(void) +{ + if(engine || Engine::state != Initialized){ + RWERROR((ERR_ENGINEOPEN)); + return 0; + } + + // Allocate engine + engine = (Engine*)malloc(sizeof(Engine)); engine->currentCamera = nil; engine->currentWorld = nil; engine->currentTexDictionary = nil; @@ -38,45 +72,78 @@ Engine::init(void) engine->loadTextures = 1; engine->makeDummies = 1; - engine->beginUpdate = null::beginUpdate; - engine->endUpdate = null::endUpdate; - engine->clearCamera = null::clearCamera; - engine->setRenderState = null::setRenderState; - engine->getRenderState = null::getRenderState; - engine->im2DRenderIndexedPrimitive = null::im2DRenderIndexedPrimitive; - engine->zNear = 0.0f; // random values - engine->zFar = 1.0f; + // Initialize device + // Device and possibly OS specific! +#ifdef RW_PS2 + engine->device = ps2::renderdevice; +#elif RW_GL3 + engine->device = gl3::renderdevice; +#elif RW_D3D9 + engine->device = d3d::renderdevice; +#else + engine->device = null::renderdevice; +#endif - ps2::initializePlatform(); - xbox::initializePlatform(); - d3d8::initializePlatform(); - d3d9::initializePlatform(); - wdgl::initializePlatform(); - gl3::initializePlatform(); + // TODO: open device; create d3d object/get video mode + + // TODO: init driver functions + ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL); + for(uint i = 0; i < NUM_PLATFORMS; i++){ + rw::engine->driver[i] = (Driver*)malloc(Driver::s_plglist[i].size); + + engine->driver[i]->defaultPipeline = defpipe; + + engine->driver[i]->rasterCreate = null::rasterCreate; + engine->driver[i]->rasterLock = null::rasterLock; + engine->driver[i]->rasterUnlock = null::rasterUnlock; + engine->driver[i]->rasterNumLevels = null::rasterNumLevels; + engine->driver[i]->rasterFromImage = null::rasterFromImage; + engine->driver[i]->rasterToImage = null::rasterToImage; + } + + Engine::state = Opened; + return 1; } -PluginList Driver::s_plglist[NUM_PLATFORMS]; +// This is where RW creates the actual rendering device +// ans calls the engine plugin ctors +bool32 +Engine::start(EngineStartParams *p) +{ + if(engine == nil || Engine::state != Opened){ + RWERROR((ERR_ENGINESTART)); + return 0; + } + + // Start device + engine->device.system(DEVICESTART, (void*)p); + engine->device.system(DEVICEINIT, nil); + + // TODO: construct engine plugins + Frame::dirtyList.init(); + for(uint i = 0; i < NUM_PLATFORMS; i++) + Driver::s_plglist[i].construct(rw::engine->driver[i]); + + // TODO: finalize device start + + Engine::state = Started; + return 1; +} void -Driver::open(void) +Engine::term(void) { - ObjPipeline *defpipe = new ObjPipeline(PLATFORM_NULL); +} - for(uint i = 0; i < NUM_PLATFORMS; i++){ - rw::driver[i] = (Driver*)malloc(s_plglist[i].size); +void +Engine::close(void) +{ +} - driver[i]->defaultPipeline = defpipe; - - driver[i]->rasterCreate = null::rasterCreate; - driver[i]->rasterLock = null::rasterLock; - driver[i]->rasterUnlock = null::rasterUnlock; - driver[i]->rasterNumLevels = null::rasterNumLevels; - driver[i]->rasterFromImage = null::rasterFromImage; - driver[i]->rasterToImage = null::rasterToImage; - - - s_plglist[i].construct(rw::driver[i]); - } +void +Engine::stop(void) +{ + engine->device.system(DEVICESTOP, nil); } namespace null { @@ -84,6 +151,7 @@ namespace null { void beginUpdate(Camera*) { } void endUpdate(Camera*) { } void clearCamera(Camera*,RGBA*,uint32) { } +void showRaster(Raster*) { } void setRenderState(int32, uint32) { } uint32 getRenderState(int32) { return 0; } @@ -129,5 +197,23 @@ rasterToImage(Raster*) return nil; } +int +deviceSystem(DeviceReq req, void *arg0) +{ + return 1; +} + +Device renderdevice = { + 0.0f, 1.0f, + null::beginUpdate, + null::endUpdate, + null::clearCamera, + null::showRaster, + null::setRenderState, + null::getRenderState, + null::im2DRenderIndexedPrimitive, + null::deviceSystem +}; + } } diff --git a/src/frame.cpp b/src/frame.cpp index d868039..ff635d2 100644 --- a/src/frame.cpp +++ b/src/frame.cpp @@ -12,6 +12,7 @@ namespace rw { LinkList Frame::dirtyList; +PluginList Frame::s_plglist = { sizeof(Frame), sizeof(Frame), nil, nil }; Frame* Frame::create(void) @@ -269,6 +270,13 @@ Frame::scale(V3d *scl, CombineOp op) updateObjects(); } +void +Frame::transform(Matrix *mat, CombineOp op) +{ + this->matrix.transform(mat, op); + updateObjects(); +} + void Frame::updateObjects(void) { diff --git a/src/geometry.cpp b/src/geometry.cpp index 2ee044d..b8f1791 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -14,6 +14,9 @@ namespace rw { +PluginList Geometry::s_plglist = { sizeof(Geometry), sizeof(Geometry), nil, nil }; +PluginList Material::s_plglist = { sizeof(Material), sizeof(Material), nil, nil }; + SurfaceProperties defaultSurfaceProps = { 1.0f, 1.0f, 1.0f }; Geometry* @@ -288,8 +291,8 @@ Geometry::calculateBoundingSphere(void) { for(int32 i = 0; i < this->numMorphTargets; i++){ MorphTarget *m = &this->morphTargets[i]; - V3d min { 1000000.0f, 1000000.0f, 1000000.0f }; - V3d max { -1000000.0f, -1000000.0f, -1000000.0f }; + V3d min = { 1000000.0f, 1000000.0f, 1000000.0f }; + V3d max = { -1000000.0f, -1000000.0f, -1000000.0f }; V3d *v = m->vertices; for(int32 j = 0; j < this->numVertices; j++){ if(v->x > max.x) max.x = v->x; diff --git a/src/geoplg.cpp b/src/geoplg.cpp index 36a164b..821735f 100644 --- a/src/geoplg.cpp +++ b/src/geoplg.cpp @@ -8,6 +8,7 @@ #include "rwplg.h" #include "rwpipeline.h" #include "rwobjects.h" +#include "rwengine.h" #include "rwanim.h" #include "rwplugins.h" #include "ps2/rwps2.h" diff --git a/src/gl/gl3.cpp b/src/gl/gl3.cpp index eaf7b5d..d4d8f1f 100644 --- a/src/gl/gl3.cpp +++ b/src/gl/gl3.cpp @@ -26,14 +26,14 @@ void* driverOpen(void *o, int32, int32) { #ifdef RW_OPENGL - driver[PLATFORM_GL3]->defaultPipeline = makeDefaultPipeline(); + engine->driver[PLATFORM_GL3]->defaultPipeline = makeDefaultPipeline(); #endif - driver[PLATFORM_GL3]->rasterNativeOffset = nativeRasterOffset; - driver[PLATFORM_GL3]->rasterCreate = rasterCreate; - driver[PLATFORM_GL3]->rasterLock = rasterLock; - driver[PLATFORM_GL3]->rasterUnlock = rasterUnlock; - driver[PLATFORM_GL3]->rasterNumLevels = rasterNumLevels; - driver[PLATFORM_GL3]->rasterFromImage = rasterFromImage; + engine->driver[PLATFORM_GL3]->rasterNativeOffset = nativeRasterOffset; + engine->driver[PLATFORM_GL3]->rasterCreate = rasterCreate; + engine->driver[PLATFORM_GL3]->rasterLock = rasterLock; + engine->driver[PLATFORM_GL3]->rasterUnlock = rasterUnlock; + engine->driver[PLATFORM_GL3]->rasterNumLevels = rasterNumLevels; + engine->driver[PLATFORM_GL3]->rasterFromImage = rasterFromImage; return o; } diff --git a/src/gl/gl3driver.cpp b/src/gl/gl3device.cpp old mode 100644 new mode 100755 similarity index 77% rename from src/gl/gl3driver.cpp rename to src/gl/gl3device.cpp index d3695db..4060eee --- a/src/gl/gl3driver.cpp +++ b/src/gl/gl3device.cpp @@ -10,10 +10,13 @@ #include "../rwengine.h" #ifdef RW_OPENGL #include +#include #include "rwgl3.h" #include "rwgl3shader.h" #include "rwgl3impl.h" +#define PLUGIN_ID 0 + namespace rw { namespace gl3 { @@ -77,7 +80,9 @@ static uint32 srcblend, destblend; static uint32 zwrite; static uint32 ztest; -uint32 blendMap[] = { +static int32 activeTexture; + +static uint32 blendMap[] = { GL_ZERO, GL_ONE, GL_SRC_COLOR, @@ -91,18 +96,26 @@ uint32 blendMap[] = { GL_SRC_ALPHA_SATURATE, }; -void +static void +setVertexAlpha(bool32 enable) +{ + if(vertexAlpha != enable){ + vertexAlpha = enable; + if(!textureAlpha){ + if(enable) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + } + } +} + +static void setRenderState(int32 state, uint32 value) { switch(state){ case VERTEXALPHA: - if(vertexAlpha != value){ - vertexAlpha = value; - if(vertexAlpha) - glEnable(GL_BLEND); - else if(!textureAlpha) - glDisable(GL_BLEND); - } + setVertexAlpha(value); break; case SRCBLEND: if(srcblend != value){ @@ -158,7 +171,7 @@ setRenderState(int32 state, uint32 value) } } -uint32 +static uint32 getRenderState(int32 state) { RGBA rgba; @@ -182,15 +195,15 @@ getRenderState(int32 state) case ALPHATESTFUNC: return uniformState.alphaFunc; case ALPHATESTREF: - return uniformState.alphaRef*255.0f; + return (uint32)(uniformState.alphaRef*255.0f); } return 0; } -void +static void resetRenderState(void) { - uniformState.alphaFunc = ALPHAGREATERTHAN; + uniformState.alphaFunc = ALPHAGREATEREQUAL; uniformState.alphaRef = 10.0f/255.0f; uniformState.fogEnable = 0; uniformState.fogStart = 0.0f; @@ -254,7 +267,7 @@ setLight(int32 n, Light *light) l->direction = m->at; } // light has position - l->w = light->getType() >= Light::POINT ? 1.0f : 0.0; + l->w = light->getType() >= Light::POINT ? 1.0f : 0.0f; l->color = light->color; l->radius = light->radius; l->minusCosAngle = light->minusCosAngle; @@ -275,11 +288,20 @@ setViewMatrix(float32 *mat) sceneDirty = 1; } +static void +setActiveTexture(int32 n) +{ + if(activeTexture != n){ + activeTexture = n; + glActiveTexture(n); + } +} + void setTexture(int32 n, Texture *tex) { bool32 alpha; - glActiveTexture(GL_TEXTURE0+n); + setActiveTexture(GL_TEXTURE0+n); if(tex == nil || tex->raster->platform != PLATFORM_GL3 || tex->raster->width == 0){ glBindTexture(GL_TEXTURE_2D, whitetex); @@ -291,12 +313,16 @@ setTexture(int32 n, Texture *tex) alpha = natras->hasAlpha; } - if(textureAlpha != alpha){ - textureAlpha = alpha; - if(textureAlpha) - glEnable(GL_BLEND); - else if(!vertexAlpha) - glDisable(GL_BLEND); + if(n == 0){ + if(alpha != textureAlpha){ + textureAlpha = alpha; + if(!vertexAlpha){ + if(alpha) + glEnable(GL_BLEND); + else + glDisable(GL_BLEND); + } + } } } @@ -323,7 +349,7 @@ flushCache(void) } } -void +static void clearCamera(Camera *cam, RGBA *col, uint32 mode) { RGBAf colf; @@ -339,7 +365,16 @@ clearCamera(Camera *cam, RGBA *col, uint32 mode) glClear(mask); } -void +static GLFWwindow *glfwwindow; + +static void +showRaster(Raster *raster) +{ + // TODO: do this properly! + glfwSwapBuffers(glfwwindow); +} + +static void beginUpdate(Camera *cam) { float view[16], proj[16]; @@ -410,17 +445,62 @@ beginUpdate(Camera *cam) } } -void -initializeRender(void) +static int +startGLFW(EngineStartParams *startparams) { - engine->beginUpdate = beginUpdate; - engine->clearCamera = clearCamera; - engine->setRenderState = setRenderState; - engine->getRenderState = getRenderState; - engine->im2DRenderIndexedPrimitive = im2DRenderIndexedPrimitive; - engine->zNear = -1.0f; - engine->zFar = 1.0f; + GLenum status; + GLFWwindow *win; + /* Init GLFW */ + if(!glfwInit()){ + RWERROR((ERR_GENERAL, "glfwInit() failed")); + return 0; + } + glfwWindowHint(GLFW_SAMPLES, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + win = glfwCreateWindow(startparams->width, startparams->height, startparams->windowtitle, 0, 0); + if(win == nil){ + RWERROR((ERR_GENERAL, "glfwCreateWindow() failed")); + glfwTerminate(); + return 0; + } + glfwMakeContextCurrent(win); + + /* Init GLEW */ + glewExperimental = GL_TRUE; + status = glewInit(); + if(status != GLEW_OK){ + RWERROR((ERR_GENERAL, glewGetErrorString(status))); + glfwDestroyWindow(win); + glfwTerminate(); + return 0; + } + if(!GLEW_VERSION_3_3){ + RWERROR((ERR_GENERAL, "OpenGL 3.3 needed")); + glfwDestroyWindow(win); + glfwTerminate(); + return 0; + } + glfwwindow = win; + *startparams->window = win; + return 1; +} + +static int +stopGLFW(void) +{ + glfwDestroyWindow(glfwwindow); + glfwTerminate(); + return 1; +} + +static int +initOpenGL(void) +{ #include "shaders/simple_gl3.inc" simpleShader = Shader::fromStrings(simple_vert_src, simple_frag_src); @@ -438,7 +518,6 @@ initializeRender(void) GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); - glGenBuffers(1, &ubo_scene); glBindBuffer(GL_UNIFORM_BUFFER, ubo_scene); glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("Scene"), ubo_scene); @@ -446,7 +525,6 @@ initializeRender(void) GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); - glGenBuffers(1, &ubo_object); glBindBuffer(GL_UNIFORM_BUFFER, ubo_object); glBindBufferBase(GL_UNIFORM_BUFFER, gl3::findBlock("Object"), ubo_object); @@ -454,7 +532,6 @@ initializeRender(void) GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); - byte whitepixel[4] = {0xFF, 0xFF, 0xFF, 0xFF}; glGenTextures(1, &whitetex); glBindTexture(GL_TEXTURE_2D, whitetex); @@ -464,7 +541,35 @@ initializeRender(void) 0, GL_RGBA, GL_UNSIGNED_BYTE, &whitepixel); im2DInit(); + return 1; } + +static int +deviceSystem(DeviceReq req, void *arg0) +{ + switch(req){ + case DEVICESTART: + return startGLFW((EngineStartParams*)arg0); + case DEVICEINIT: + return initOpenGL(); + case DEVICESTOP: + return stopGLFW(); + } + return 1; +} + +Device renderdevice = { + -1.0f, 1.0f, + gl3::beginUpdate, + null::endUpdate, + gl3::clearCamera, + gl3::showRaster, + gl3::setRenderState, + gl3::getRenderState, + gl3::im2DRenderIndexedPrimitive, + gl3::deviceSystem +}; + } } diff --git a/src/gl/gl3render.cpp b/src/gl/gl3render.cpp index 90783b7..fd345a7 100644 --- a/src/gl/gl3render.cpp +++ b/src/gl/gl3render.cpp @@ -43,7 +43,7 @@ void lightingCB(void) { World *world; - RGBAf ambLight = (RGBAf){0.0, 0.0, 0.0, 1.0}; + RGBAf ambLight = { 0.0, 0.0, 0.0, 1.0 }; int n = 0; world = (World*)engine->currentWorld; @@ -84,9 +84,6 @@ defaultRenderCB(Atomic *atomic, InstanceDataHeader *header) InstanceData *inst = header->inst; int32 n = header->numMeshes; -// rw::setRenderState(ALPHATESTFUNC, 1); -// rw::setRenderState(ALPHATESTREF, 50); - simpleShader->use(); while(n--){ diff --git a/src/gl/gl3shader.cpp b/src/gl/gl3shader.cpp index be879a0..fa16bb8 100644 --- a/src/gl/gl3shader.cpp +++ b/src/gl/gl3shader.cpp @@ -189,8 +189,10 @@ Shader::fromFiles(const char *vspath, const char *fspath) void Shader::use(void) { - glUseProgram(this->program); - currentShader = this; + if(currentShader != this){ + glUseProgram(this->program); + currentShader = this; + } } } diff --git a/src/gl/rwgl3.h b/src/gl/rwgl3.h index 0a51e9a..313ea6d 100644 --- a/src/gl/rwgl3.h +++ b/src/gl/rwgl3.h @@ -1,8 +1,24 @@ +#ifdef RW_GL3 +#include +#include +#endif + namespace rw { + +#ifdef RW_GL3 +struct EngineStartParams +{ + GLFWwindow **window; + int width, height; + const char *windowtitle; +}; +#endif + namespace gl3 { void initializePlatform(void); -void initializeRender(void); + +extern Device renderdevice; // arguments to glVertexAttribPointer basically struct AttribDesc diff --git a/src/gl/shaders/im2d.frag b/src/gl/shaders/im2d.frag index b40c2f9..91bfc3e 100644 --- a/src/gl/shaders/im2d.frag +++ b/src/gl/shaders/im2d.frag @@ -10,6 +10,6 @@ out vec4 color; void main(void) { - color = v_color*texture2D(tex, vec2(v_tex0.x, v_tex0.y)); + color = v_color*texture(tex, vec2(v_tex0.x, v_tex0.y)); } diff --git a/src/gl/shaders/im2d_gl3.inc b/src/gl/shaders/im2d_gl3.inc index 23af07c..6230350 100644 --- a/src/gl/shaders/im2d_gl3.inc +++ b/src/gl/shaders/im2d_gl3.inc @@ -36,7 +36,7 @@ const char *im2d_frag_src = "void\n" "main(void)\n" "{\n" -" color = v_color*texture2D(tex, vec2(v_tex0.x, v_tex0.y));\n" +" color = v_color*texture(tex, vec2(v_tex0.x, v_tex0.y));\n" "}\n" ; diff --git a/src/gl/shaders/matfx_env.frag b/src/gl/shaders/matfx_env.frag index 5c9522d..ed90362 100644 --- a/src/gl/shaders/matfx_env.frag +++ b/src/gl/shaders/matfx_env.frag @@ -17,7 +17,7 @@ out vec4 color; void main(void) { - color = v_color*texture2D(tex, vec2(v_tex0.x, v_tex0.y)); + color = v_color*texture(tex, vec2(v_tex0.x, v_tex0.y)); switch(u_alphaTest){ default: case 0: break; diff --git a/src/gl/shaders/matfx_gl3.inc b/src/gl/shaders/matfx_gl3.inc index 3a8f5f5..8b65b64 100644 --- a/src/gl/shaders/matfx_gl3.inc +++ b/src/gl/shaders/matfx_gl3.inc @@ -78,7 +78,7 @@ const char *matfx_env_frag_src = "void\n" "main(void)\n" "{\n" -" color = v_color*texture2D(tex, vec2(v_tex0.x, v_tex0.y));\n" +" color = v_color*texture(tex, vec2(v_tex0.x, v_tex0.y));\n" " switch(u_alphaTest){\n" " default:\n" " case 0: break;\n" diff --git a/src/gl/shaders/simple.frag b/src/gl/shaders/simple.frag index 11b2939..770d62b 100644 --- a/src/gl/shaders/simple.frag +++ b/src/gl/shaders/simple.frag @@ -22,7 +22,7 @@ out vec4 color; void main(void) { - color = v_color*texture2D(tex, vec2(v_tex0.x, v_tex0.y)); + color = v_color*texture(tex, vec2(v_tex0.x, v_tex0.y)); if(u_fogEnable != 0) color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog); switch(u_alphaTest){ diff --git a/src/gl/shaders/simple_gl3.inc b/src/gl/shaders/simple_gl3.inc index 6d0e614..76a21f8 100644 --- a/src/gl/shaders/simple_gl3.inc +++ b/src/gl/shaders/simple_gl3.inc @@ -95,7 +95,7 @@ const char *simple_frag_src = "void\n" "main(void)\n" "{\n" -" color = v_color*texture2D(tex, vec2(v_tex0.x, v_tex0.y));\n" +" color = v_color*texture(tex, vec2(v_tex0.x, v_tex0.y));\n" " if(u_fogEnable != 0)\n" " color.rgb = mix(u_fogColor.rgb, color.rgb, v_fog);\n" " switch(u_alphaTest){\n" diff --git a/src/gl/wdgl.cpp b/src/gl/wdgl.cpp index 60029ef..cd4def3 100644 --- a/src/gl/wdgl.cpp +++ b/src/gl/wdgl.cpp @@ -25,7 +25,7 @@ namespace wdgl { void* driverOpen(void *o, int32, int32) { - driver[PLATFORM_WDGL]->defaultPipeline = makeDefaultPipeline(); + engine->driver[PLATFORM_WDGL]->defaultPipeline = makeDefaultPipeline(); return o; } @@ -820,7 +820,7 @@ Texture::upload(void) switch(r->format & 0xF00){ case Raster::C8888: glTexImage2D(GL_TEXTURE_2D, 0, 4, r->width, r->height, - 0, GL_RGBA, GL_UNSIGNED_BYTE, r->texels); + 0, GL_RGBA, GL_UNSIGNED_BYTE, r->pixels); break; default: printf("unsupported raster format: %x\n", r->format); diff --git a/src/hanim.cpp b/src/hanim.cpp index 32b824c..d2daf6e 100644 --- a/src/hanim.cpp +++ b/src/hanim.cpp @@ -8,6 +8,7 @@ #include "rwplg.h" #include "rwpipeline.h" #include "rwobjects.h" +#include "rwengine.h" #include "rwanim.h" #include "rwplugins.h" #include "ps2/rwps2.h" diff --git a/src/image.cpp b/src/image.cpp index fd97f49..e32606e 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -24,6 +24,10 @@ namespace rw { +PluginList TexDictionary::s_plglist = { sizeof(TexDictionary), sizeof(TexDictionary), nil, nil }; +PluginList Texture::s_plglist = { sizeof(Texture), sizeof(Texture), nil, nil }; +PluginList Raster::s_plglist = { sizeof(Raster), sizeof(Raster), nil, nil }; + // // TexDictionary // @@ -904,6 +908,7 @@ Image::getFilename(const char *name) Raster* Raster::create(int32 width, int32 height, int32 depth, int32 format, int32 platform) { + // TODO: pass arguments through to the driver and create the raster there Raster *raster = (Raster*)malloc(s_plglist.size); assert(raster != nil); raster->platform = platform ? platform : rw::platform; @@ -913,11 +918,11 @@ Raster::create(int32 width, int32 height, int32 depth, int32 format, int32 platf raster->width = width; raster->height = height; raster->depth = depth; - raster->texels = raster->palette = nil; + raster->pixels = raster->palette = nil; s_plglist.construct(raster); // printf("%d %d %d %d\n", raster->type, raster->width, raster->height, raster->depth); - driver[raster->platform]->rasterCreate(raster); + engine->driver[raster->platform]->rasterCreate(raster); return raster; } @@ -933,19 +938,19 @@ Raster::destroy(void) uint8* Raster::lock(int32 level) { - return driver[this->platform]->rasterLock(this, level); + return engine->driver[this->platform]->rasterLock(this, level); } void Raster::unlock(int32 level) { - driver[this->platform]->rasterUnlock(this, level); + engine->driver[this->platform]->rasterUnlock(this, level); } int32 Raster::getNumLevels(void) { - return driver[this->platform]->rasterNumLevels(this); + return engine->driver[this->platform]->rasterNumLevels(this); } int32 @@ -964,14 +969,14 @@ Raster::createFromImage(Image *image, int32 platform) Raster *raster = Raster::create(image->width, image->height, image->depth, TEXTURE | DONTALLOCATE, platform); - driver[raster->platform]->rasterFromImage(raster, image); + engine->driver[raster->platform]->rasterFromImage(raster, image); return raster; } Image* Raster::toImage(void) { - return driver[this->platform]->rasterToImage(this); + return engine->driver[this->platform]->rasterToImage(this); } } diff --git a/src/light.cpp b/src/light.cpp index 55eeba0..21ced14 100644 --- a/src/light.cpp +++ b/src/light.cpp @@ -11,6 +11,8 @@ namespace rw { +PluginList Light::s_plglist = { sizeof(Light), sizeof(Light), nil, nil }; + static void lightSync(ObjectWithFrame*) { diff --git a/src/matfx.cpp b/src/matfx.cpp old mode 100644 new mode 100755 index 777c065..70bea42 --- a/src/matfx.cpp +++ b/src/matfx.cpp @@ -145,7 +145,7 @@ MatFX::get(Material *m) return *PLUGINOFFSET(MatFX*, m, matFXGlobals.materialOffset); } -uint32 +int32 MatFX::getEffectIndex(uint32 type) { for(int i = 0; i < 2; i++) diff --git a/src/pipeline.cpp b/src/pipeline.cpp old mode 100644 new mode 100755 index 0cd936b..dfe1c75 --- a/src/pipeline.cpp +++ b/src/pipeline.cpp @@ -7,7 +7,6 @@ #include "rwplg.h" #include "rwpipeline.h" #include "rwobjects.h" -#include "ps2/rwps2.h" #define COLOR_ARGB(a,r,g,b) \ ((uint32)((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff))) diff --git a/src/ps2/pds.cpp b/src/ps2/pds.cpp old mode 100644 new mode 100755 index 449a2f4..53d977d --- a/src/ps2/pds.cpp +++ b/src/ps2/pds.cpp @@ -7,6 +7,7 @@ #include "../rwplg.h" #include "../rwpipeline.h" #include "../rwobjects.h" +#include "../rwengine.h" #include "../rwanim.h" #include "../rwplugins.h" #include "rwps2.h" diff --git a/src/ps2/ps2.cpp b/src/ps2/ps2.cpp old mode 100644 new mode 100755 index ec29a1c..1407532 --- a/src/ps2/ps2.cpp +++ b/src/ps2/ps2.cpp @@ -24,13 +24,13 @@ namespace ps2 { void* driverOpen(void *o, int32, int32) { - driver[PLATFORM_PS2]->defaultPipeline = makeDefaultPipeline(); + engine->driver[PLATFORM_PS2]->defaultPipeline = makeDefaultPipeline(); - driver[PLATFORM_PS2]->rasterNativeOffset = nativeRasterOffset; - driver[PLATFORM_PS2]->rasterCreate = rasterCreate; - driver[PLATFORM_PS2]->rasterLock = rasterLock; - driver[PLATFORM_PS2]->rasterUnlock = rasterUnlock; - driver[PLATFORM_PS2]->rasterNumLevels = rasterNumLevels; + engine->driver[PLATFORM_PS2]->rasterNativeOffset = nativeRasterOffset; + engine->driver[PLATFORM_PS2]->rasterCreate = rasterCreate; + engine->driver[PLATFORM_PS2]->rasterLock = rasterLock; + engine->driver[PLATFORM_PS2]->rasterUnlock = rasterUnlock; + engine->driver[PLATFORM_PS2]->rasterNumLevels = rasterNumLevels; return o; } @@ -73,7 +73,7 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) Geometry *geometry = (Geometry*)object; uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, nil)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); @@ -92,7 +92,6 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) uint32 buf[2]; stream->read(buf, 8); instance->dataSize = buf[0]; - instance->arePointersFixed = buf[1]; // TODO: force alignment instance->data = new uint8[instance->dataSize]; #ifdef RW_PS2 @@ -100,6 +99,10 @@ readNativeData(Stream *stream, int32, void *object, int32, int32) assert(a % 0x10 == 0); #endif stream->read(instance->data, instance->dataSize); +#ifdef RW_PS2 + if(!buf[1]) + fixDmaOffsets(instance); +#endif instance->material = geometry->meshHeader->mesh[i].material; // sizedebug(instance); } @@ -118,13 +121,15 @@ writeNativeData(Stream *stream, int32 len, void *object, int32, int32) InstanceDataHeader *header = (InstanceDataHeader*)geometry->instData; for(uint32 i = 0; i < header->numMeshes; i++){ InstanceData *instance = &header->instanceMeshes[i]; - if(instance->arePointersFixed == 2) - unfixDmaOffsets(instance); uint32 buf[2]; buf[0] = instance->dataSize; - buf[1] = instance->arePointersFixed; + buf[1] = unfixDmaOffsets(instance); stream->write(buf, 8); stream->write(instance->data, instance->dataSize); +#ifdef RW_PS2 + if(!buf[1]) + fixDmaOffsets(instance); +#endif } return stream; } @@ -157,13 +162,11 @@ registerNativeDataPlugin(void) getSizeNativeData); } +// Patch DMA ref ADDR fields to point to the actual data. #ifdef RW_PS2 void fixDmaOffsets(InstanceData *inst) { - if(inst->arePointersFixed) - return; - uint32 base = (uint32)inst->data; uint32 *tag = (uint32*)inst->data; for(;;){ @@ -184,7 +187,6 @@ fixDmaOffsets(InstanceData *inst) // DMAret case 0x60000000: // we're done - inst->arePointersFixed = 2; return; default: @@ -195,15 +197,17 @@ fixDmaOffsets(InstanceData *inst) } #endif -void +// Patch DMA ref ADDR fields to qword offsets and return whether +// no ref tags were found. +// Only under RW_PS2 are the addresses actually patched but we need +// the return value for streaming out. +bool32 unfixDmaOffsets(InstanceData *inst) { - (void)inst; + bool32 norefs = 1; #ifdef RW_PS2 - if(inst->arePointersFixed != 2) - return; - uint32 base = (uint32)inst->data; +#endif uint32 *tag = (uint32*)inst->data; for(;;){ switch(tag[0]&0x70000000){ @@ -215,23 +219,23 @@ unfixDmaOffsets(InstanceData *inst) // DMAref case 0x30000000: + norefs = 0; // unfix address and jump to next +#ifdef RW_PS2 tag[1] = (tag[1] - base)>>4; +#endif tag += 4; break; // DMAret case 0x60000000: - // we're done - inst->arePointersFixed = 0; - return; + return norefs; default: fprintf(stderr, "error: unknown DMAtag %X\n", tag[0]); - return; + return norefs; } } -#endif } // Pipeline @@ -586,7 +590,6 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m) InstMeshInfo im = getInstMeshInfo(this, g, m); inst->dataSize = (im.size+im.size2)<<4; - inst->arePointersFixed = im.numBrokenAttribs == 0; // TODO: force alignment inst->data = new uint8[inst->dataSize]; @@ -685,6 +688,10 @@ MatPipeline::instance(Geometry *g, InstanceData *inst, Mesh *m) if(this->instanceCB) this->instanceCB(this, g, m, datap); +#ifdef RW_PS2 + if(im.numBrokenAttribs) + fixDmaOffsets(inst); +#endif } uint8* @@ -766,6 +773,7 @@ objInstance(rw::ObjPipeline *rwpipe, Atomic *atomic) geo->flags |= Geometry::NATIVE; } +/* static void printVertCounts(InstanceData *inst, int flag) { @@ -794,6 +802,7 @@ printVertCounts(InstanceData *inst, int flag) } } } +*/ static void objUninstance(rw::ObjPipeline *rwpipe, Atomic *atomic) @@ -1241,6 +1250,7 @@ registerADCPlugin(void) } // misc stuff +/* void printDMA(InstanceData *inst) @@ -1300,6 +1310,7 @@ sizedebug(InstanceData *inst) } } } +*/ } } diff --git a/src/ps2/ps2device.cpp b/src/ps2/ps2device.cpp new file mode 100755 index 0000000..f40a9b6 --- /dev/null +++ b/src/ps2/ps2device.cpp @@ -0,0 +1,41 @@ +#ifdef RW_PS2 + +#include +#include +#include +#include + +#include "../rwbase.h" +#include "../rwerror.h" +#include "../rwplg.h" +#include "../rwpipeline.h" +#include "../rwobjects.h" +#include "../rwengine.h" +#include "../rwanim.h" +#include "../rwplugins.h" +#include "rwps2.h" +#include "rwps2plg.h" + +#include "rwps2impl.h" + +#define PLUGIN_ID 2 + +namespace rw { +namespace ps2 { + +Device renderdevice = { + 16777215.0f, 0.0f, + null::beginUpdate, + null::endUpdate, + null::clearCamera, + null::showRaster, + null::setRenderState, + null::getRenderState, + null::im2DRenderIndexedPrimitive, + null::deviceSystem +}; + +} +} + +#endif diff --git a/src/ps2/ps2raster.cpp b/src/ps2/ps2raster.cpp index 363e45b..292e7a8 100644 --- a/src/ps2/ps2raster.cpp +++ b/src/ps2/ps2raster.cpp @@ -13,6 +13,7 @@ #define PLUGIN_ID 0 +#define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) namespace rw { @@ -23,45 +24,6 @@ int32 nativeRasterOffset; #define MAXLEVEL(r) ((r)->tex1low >> 2) static bool32 noNewStyleRasters; -// i don't really understand this, stolen from RW -static void -ps2MinSize(int32 psm, int32 flags, int32 *minw, int32 *minh) -{ - *minh = 1; - switch(psm){ - case 0x00: - case 0x30: - *minw = 2; // 32 bit - break; - case 0x02: - case 0x0A: - case 0x32: - case 0x3A: - *minw = 4; // 16 bit - break; - case 0x01: - case 0x13: - case 0x14: - case 0x1B: - case 0x24: - case 0x2C: - case 0x31: - *minw = 8; // everything else - break; - } - if(flags & 0x2 && psm == 0x13){ // PSMT8 - *minw = 16; - *minh = 4; - } - if(flags & 0x4 && psm == 0x14){ // PSMT4 - *minw = 32; - *minh = 4; - } -} - -#define ALIGN16(x) ((x) + 0xF & ~0xF) -#define ALIGN64(x) ((x) + 0x3F & ~0x3F) - enum Psm { PSMCT32 = 0x0, PSMCT24 = 0x1, @@ -72,8 +34,53 @@ enum Psm { PSMT8H = 0x1B, PSMT4HL = 0x24, PSMT4HH = 0x2C, + PSMZ32 = 0x30, + PSMZ24 = 0x31, + PSMZ16 = 0x32, + PSMZ16S = 0x3A, }; +// i don't really understand this, stolen from RW +static void +transferMinSize(int32 psm, int32 flags, int32 *minw, int32 *minh) +{ + *minh = 1; + switch(psm){ + case PSMCT32: + case PSMZ32: + *minw = 2; // 32 bit + break; + case PSMCT16: + case PSMCT16S: + case PSMZ16: + case PSMZ16S: + *minw = 4; // 16 bit + break; + case PSMCT24: + case PSMT8: + case PSMT4: + case PSMT8H: + case PSMT4HL: + case PSMT4HH: + case PSMZ24: + *minw = 8; // everything else + break; + } + if(flags & 0x2 && psm == PSMT8){ + *minw = 16; + *minh = 4; + } + if(flags & 0x4 && psm == PSMT4){ + *minw = 32; + *minh = 4; + } +} + +#define ALIGN(x,a) ((x) + (a)-1 & ~((a)-1)) +#define ALIGN16(x) ((x) + 0xF & ~0xF) +#define ALIGN64(x) ((x) + 0x3F & ~0x3F) +#define NSIZE(dim,pagedim) (((dim) + (pagedim)-1)/(pagedim)) + void* mallocalign(size_t size, int32 alignment) { @@ -95,106 +102,771 @@ freealign(void *p) free(pp); } -void -rasterCreate(Raster *raster) +// TODO: these depend on video mode, set in deviceSystem! +int32 cameraFormat = Raster::C8888; +int32 cameraDepth = 32; +int32 cameraZDepth = 16; + +int32 defaultMipMapKL = 0xFC0; +int32 maxMipLevels = 7; + +int32 +getRasterFormat(Raster *raster) { + int32 palformat, pixelformat, mipmapflags; + pixelformat = raster->format & 0xF00; + palformat = raster->format & 0x6000; + mipmapflags = raster->format & 0x9000; + switch(raster->type){ + case Raster::ZBUFFER: + if(palformat || mipmapflags){ + RWERROR((ERR_INVRASTER)); + return 0; + } + if(raster->depth && raster->depth != cameraZDepth){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = cameraZDepth; + if(pixelformat){ + if(raster->depth == 16 && pixelformat != Raster::D16 || + raster->depth == 32 && pixelformat != Raster::D32){ + RWERROR((ERR_INVRASTER)); + return 0; + } + } + pixelformat = raster->depth == 16 ? Raster::D16 : Raster::D32; + raster->format = pixelformat; + break; + case Raster::CAMERA: + if(palformat || mipmapflags){ + RWERROR((ERR_INVRASTER)); + return 0; + } + if(raster->depth && raster->depth != cameraDepth){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = cameraDepth; + if(pixelformat && pixelformat != cameraFormat){ + RWERROR((ERR_INVRASTER)); + return 0; + } + pixelformat = cameraFormat; + raster->format = pixelformat; + break; + case Raster::NORMAL: + case Raster::CAMERATEXTURE: + if(palformat || mipmapflags){ + RWERROR((ERR_INVRASTER)); + return 0; + } + /* fallthrough */ + case Raster::TEXTURE: + // Find raster format by depth if none was given + if(pixelformat == 0) + switch(raster->depth){ + case 4: + pixelformat = Raster::C1555; + palformat = Raster::PAL4; + break; + case 8: + pixelformat = Raster::C1555; + palformat = Raster::PAL8; + break; + case 24: + pixelformat = Raster::C888; + palformat = 0; + break; + case 32: + pixelformat = Raster::C8888; + palformat = 0; + break; + default: + pixelformat = Raster::C1555; + palformat = 0; + break; + } + raster->format = pixelformat | palformat | mipmapflags; + // Sanity check raster format and depth; set depth if none given + if(palformat){ + if(palformat == Raster::PAL8){ + if(raster->depth && raster->depth != 8){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = 8; + if(pixelformat != Raster::C1555 && pixelformat != Raster::C8888){ + RWERROR((ERR_INVRASTER)); + return 0; + } + }else if(palformat == Raster::PAL4){ + if(raster->depth && raster->depth != 4){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = 4; + if(pixelformat != Raster::C1555 && pixelformat != Raster::C8888){ + RWERROR((ERR_INVRASTER)); + return 0; + } + }else{ + RWERROR((ERR_INVRASTER)); + return 0; + } + }else if(pixelformat == Raster::C1555){ + if(raster->depth && raster->depth != 16){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = 16; + }else if(pixelformat == Raster::C8888){ + if(raster->depth && raster->depth != 32){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = 32; + }else if(pixelformat == Raster::C888){ + if(raster->depth && raster->depth != 24){ + RWERROR((ERR_INVRASTER)); + return 0; + } + raster->depth = 24; + }else{ + RWERROR((ERR_INVRASTER)); + return 0; + } + break; + default: + RWERROR((ERR_INVRASTER)); + return 0; + } + return 1; +} + +/* + * Memory units: + * Column: 64 bytes (single cycle access) + * Block: 256 bytes, 64 words, 4 columns. texture base pointers + * Page: 8 kbytes, 2 kwords, 128 columns, 32 blocks. frame buffer base pointers + * entire memory: 4 mbytes, 64k columns, 16k blocks, 512 pages + * + * PSMT4: 128x128 pixels, 4x8 blocks per page, 32x16 pixels per block + * PSMT8: 128x64 pixels, 8x4 blocks per page, 16x16 pixels per block + * PSMCT16(S): 64x64 pixels, 4x8 blocks per page, 16x8 pixels per block + * PSMCT24: 64x32 pixels, 8x4 blocks per page, 8x8 pixels per block + * PSMCT32: 64x32 pixels, 8x4 blocks per page, 8x8 pixels per block + * + * Layout of blocks in page: + * + * PSMCT24, PSMCT32, PSMT8 + * +----+----+----+----+----+----+----+----+ + * | 0 | 1 | 4 | 5 | 16 | 17 | 20 | 21 | + * +----+----+----+----+----+----+----+----+ + * | 2 | 3 | 6 | 7 | 18 | 19 | 22 | 23 | + * +----+----+----+----+----+----+----+----+ + * | 8 | 9 | 12 | 13 | 24 | 25 | 28 | 29 | + * +----+----+----+----+----+----+----+----+ + * | 10 | 11 | 14 | 15 | 26 | 27 | 30 | 31 | + * +----+----+----+----+----+----+----+----+ + * + * PSMCT16, PSMT4 + * +----+----+----+----+ + * | 0 | 2 | 8 | 10 | + * +----+----+----+----+ + * | 1 | 3 | 9 | 11 | + * +----+----+----+----+ + * | 4 | 6 | 12 | 14 | + * +----+----+----+----+ + * | 5 | 7 | 13 | 15 | + * +----+----+----+----+ + * | 16 | 18 | 24 | 26 | + * +----+----+----+----+ + * | 17 | 19 | 25 | 27 | + * +----+----+----+----+ + * | 20 | 22 | 28 | 30 | + * +----+----+----+----+ + * | 21 | 23 | 29 | 31 | + * +----+----+----+----+ + * + * PSMCT16S + * +----+----+----+----+ + * | 0 | 2 | 16 | 18 | + * +----+----+----+----+ + * | 1 | 3 | 17 | 19 | + * +----+----+----+----+ + * | 8 | 10 | 24 | 26 | + * +----+----+----+----+ + * | 9 | 11 | 25 | 27 | + * +----+----+----+----+ + * | 4 | 6 | 20 | 22 | + * +----+----+----+----+ + * | 5 | 7 | 21 | 23 | + * +----+----+----+----+ + * | 12 | 14 | 28 | 30 | + * +----+----+----+----+ + * | 13 | 15 | 29 | 31 | + * +----+----+----+----+ + * + */ + +static uint8 blockmap_PSMCT32[32] = { + 0, 1, 4, 5, 16, 17, 20, 21, + 2, 3, 6, 7, 18, 19, 22, 23, + 8, 9, 12, 13, 24, 25, 28, 29, + 10, 11, 14, 15, 26, 27, 30, 31, +}; +static uint8 blockmap_PSMCT16[32] = { + 0, 2, 8, 10, + 1, 3, 9, 11, + 4, 6, 12, 14, + 5, 7, 13, 15, + 16, 18, 24, 26, + 17, 19, 25, 27, + 20, 22, 28, 30, + 21, 23, 29, 31, +}; +static uint8 blockmap_PSMCT16S[32] = { + 0, 2, 16, 18, + 1, 3, 17, 19, + 8, 10, 24, 26, + 9, 11, 25, 27, + 4, 6, 20, 22, + 5, 7, 21, 23, + 12, 14, 28, 30, + 13, 15, 29, 31, +}; +static uint8 blockmap_PSMZ32[32] = { + 24, 25, 28, 29, 8, 9, 12, 13, + 26, 27, 30, 31, 10, 11, 14, 15, + 16, 17, 20, 21, 0, 1, 4, 5, + 18, 19, 22, 23, 2, 3, 6, 7, +}; +static uint8 blockmap_PSMZ16[32] = { + 24, 26, 16, 18, + 25, 27, 17, 19, + 28, 30, 20, 22, + 29, 31, 21, 23, + 8, 10, 0, 2, + 9, 11, 1, 3, + 12, 14, 4, 6, + 13, 15, 5, 7, +}; +static uint8 blockmap_PSMZ16S[32] = { + 24, 26, 8, 10, + 25, 27, 9, 11, + 16, 18, 0, 2, + 17, 19, 1, 3, + 28, 30, 12, 14, + 29, 31, 13, 15, + 20, 22, 4, 6, + 21, 23, 5, 7, +}; + +static uint8 blockmaprev_PSMCT32[32] = { + 0, 1, 8, 9, 2, 3, 10, 11, + 16, 17, 24, 25, 18, 19, 26, 27, + 4, 5, 12, 13, 6, 7, 14, 15, + 20, 21, 28, 29, 22, 23, 30, 31, +}; +static uint8 blockmaprev_PSMCT16[32] = { + 0, 4, 1, 5, + 8, 12, 9, 13, + 2, 6, 3, 7, + 10, 14, 11, 15, + 16, 20, 17, 21, + 24, 28, 25, 29, + 18, 22, 19, 23, + 26, 30, 27, 31, +}; + +/* Suffixes used: + * _Px - pixels + * _W - width units (pixels/64) + * _B - blocks + * _P - pages + */ + +/* Layout mipmaps and palette in GS memory */ +static void +calcOffsets(int32 width_Px, int32 height_Px, int32 psm, uint64 *bufferBase_B, uint64 *bufferWidth_W, uint32 *trxpos, uint32 *totalSize, uint32 *paletteBase) +{ + int32 pageWidth_Px, pageHeight_Px; + int32 blockWidth_Px, blockHeight_Px; + int32 mindim_Px; + int32 nlevels; + int32 n; + int32 mipw_Px, miph_Px; + int32 lastmipw_Px, lastmiph_Px; + uint32 bufferHeight_P[8]; + uint32 bufferPage_B[8]; // address of page in which the level is allocated + uint32 xoff_Px, yoff_Px; // x/y offset the last level starts at + // Whenever we allocate horizontally inside a page, + // keep track of the region below it on this stack. + uint32 sp; + uint32 xoffstack_Px[8]; // actually unused... + uint32 widthstack_Px[8]; + uint32 heightstack_Px[8]; + uint32 basestack_B[8]; + int32 flag; + + switch(psm){ + case PSMCT32: + case PSMCT24: + case PSMT8H: + case PSMT4HL: + case PSMT4HH: + case PSMZ32: + case PSMZ24: + pageWidth_Px = 64; + pageHeight_Px = 32; + blockWidth_Px = 8; + blockHeight_Px = 8; + break; + case PSMT8: + pageWidth_Px = 128; + pageHeight_Px = 64; + blockWidth_Px = 16; + blockHeight_Px = 16; + break; + case PSMT4: + pageWidth_Px = 128; + pageHeight_Px = 128; + blockWidth_Px = 32; + blockHeight_Px = 16; + break; + case PSMCT16: + case PSMCT16S: + case PSMZ16: + case PSMZ16S: + default: + pageWidth_Px = 64; + pageHeight_Px = 64; + blockWidth_Px = 16; + blockHeight_Px = 8; + break; + } + + mindim_Px = min(width_Px, height_Px); + for(nlevels = 1; mindim_Px > 8; nlevels++){ + if(nlevels >= maxMipLevels) + break; + mindim_Px /= 2; + } + +#define PAGEWIDTH_B (pageWidth_Px/blockWidth_Px) // number of horizontal blocks per page +#define NBLKX(dim) (NSIZE((dim), blockWidth_Px)) +#define NBLKY(dim) (NSIZE((dim), blockHeight_Px)) +#define NPGX(dim) (NSIZE((dim), pageWidth_Px)) +#define NPGY(dim) (NSIZE((dim), pageHeight_Px)) +#define REALWIDTH(w) (max((w), blockWidth_Px)) +#define REALHEIGHT(w) (max((w), blockHeight_Px)) + + bufferBase_B[0] = 0; + bufferWidth_W[0] = NPGX(width_Px)*pageWidth_Px/64; + bufferHeight_P[0] = NPGY(height_Px); + bufferPage_B[0] = 0; + lastmipw_Px = width_Px; + lastmiph_Px = height_Px; + sp = 0; + xoff_Px = 0; + yoff_Px = 0; + flag = 0; + // Calculate info for all mipmap levels. + // mipwidth/height are actually the dimensions of level n-1! + // This code was reversed from RW and is rather complicated... + // partially because it's not clear what the assumptions are, + // can width/height be non-powers of 2? + for(n = 1; n < nlevels; n++){ + mipw_Px = lastmipw_Px/2; + miph_Px = lastmiph_Px/2; + if(lastmipw_Px >= pageWidth_Px){ + if(lastmiph_Px >= pageHeight_Px){ + // CASE 0 + // We allocate full pages + // This is the only place bufferWidth can change. Similarly bufferBase_2, which is related + bufferBase_B[n] = bufferBase_B[n-1] + (lastmipw_Px/blockWidth_Px)*(lastmiph_Px/blockHeight_Px); + bufferPage_B[n] = bufferBase_B[n]; + bufferWidth_W[n] = NPGX(mipw_Px)*pageWidth_Px/64; + bufferHeight_P[n] = NPGY(miph_Px); + xoff_Px = 0; + yoff_Px = 0; + }else{ + // CASE 1 + // Allocate vertically in the current page + bufferPage_B[n] = bufferPage_B[n-1]; + bufferHeight_P[n] = bufferHeight_P[n-1]; + bufferWidth_W[n] = bufferWidth_W[n-1]; + // How do we know pageHeight - yoff - REALHEIGHT(lastmiph) >= miph? + // And how is this condition ever false? + // Assuming lastmipw >= pageWidth for any number of levels, lastmiph must be pageHeight/2 + // or lower to reach this code. No dimension is lower than 8. Then consequent mipmaps + // will have heights halved but even with PSMT4 we will only (vertically) fill the + // page with the last mipmap and not go beyond... + if(REALHEIGHT(lastmiph_Px) + yoff_Px < pageHeight_Px){ + // CASE 2 + yoff_Px += REALHEIGHT(lastmiph_Px); + bufferBase_B[n] = bufferBase_B[n-1] + + PAGEWIDTH_B * NBLKY(lastmiph_Px) * + bufferWidth_W[n]*64/pageWidth_Px; // number of horizontal pages for level + }else{ + // CASE 3 + // Can this happen? + xoff_Px += REALWIDTH(lastmipw_Px); + bufferBase_B[n] = bufferBase_B[n-1] + NBLKX(lastmipw_Px); + } + } + }else if(lastmiph_Px >= pageHeight_Px){ + // CASE 4 + // Allocate horizontally + bufferPage_B[n] = bufferPage_B[n-1]; + bufferHeight_P[n] = bufferHeight_P[n-1]; + bufferWidth_W[n] = bufferWidth_W[n-1]; + if(REALWIDTH(lastmipw_Px) + xoff_Px < pageWidth_Px){ + // CASE 5 + xoffstack_Px[sp] = xoff_Px; // unused... + heightstack_Px[sp] = REALHEIGHT(lastmiph_Px); + widthstack_Px[sp] = REALWIDTH(lastmipw_Px); + basestack_B[sp] = bufferBase_B[n-1] + NBLKY(lastmiph_Px) * PAGEWIDTH_B; + sp++; + xoff_Px += REALWIDTH(lastmipw_Px); + bufferBase_B[n] = bufferBase_B[n-1] + NBLKX(lastmipw_Px); + }else if(sp){ + // CASE 7 + bufferBase_B[n] = basestack_B[sp-1]; + if(REALWIDTH(mipw_Px) < widthstack_Px[sp-1]){ + // CASE 9 + basestack_B[sp-1] += NBLKX(mipw_Px); + widthstack_Px[sp-1] -= REALWIDTH(mipw_Px); + }else if(REALHEIGHT(miph_Px) < heightstack_Px[sp-1]){ + // CASE 8 + basestack_B[sp-1] += NBLKY(miph_Px) * PAGEWIDTH_B; + heightstack_Px[sp-1] -= REALHEIGHT(miph_Px); + }else{ + // CASE 10 + sp--; + } + flag = 1; + }else{ + // CASE 6 + yoff_Px += REALHEIGHT(lastmiph_Px); + bufferBase_B[n] = bufferBase_B[n-1] + PAGEWIDTH_B*NBLKY(lastmiph_Px); + } + }else{ + // CASE 11 + bufferHeight_P[n] = bufferHeight_P[n-1]; + bufferPage_B[n] = bufferPage_B[n-1]; + bufferWidth_W[n] = bufferWidth_W[n-1]; + if(REALWIDTH(lastmipw_Px) + xoff_Px < bufferWidth_W[n-1]*64){ + // CASE 12 + xoffstack_Px[sp] = xoff_Px; // unused... + widthstack_Px[sp] = REALWIDTH(lastmipw_Px); + heightstack_Px[sp] = REALHEIGHT(lastmiph_Px); + basestack_B[sp] = bufferBase_B[n-1] + PAGEWIDTH_B * NBLKY(lastmiph_Px); + sp++; + xoff_Px += REALWIDTH(lastmipw_Px); + bufferBase_B[n] = bufferBase_B[n-1] + NBLKX(lastmipw_Px); + }else if(REALHEIGHT(lastmiph_Px) + yoff_Px < pageHeight_Px*bufferHeight_P[n] && flag == 0){ + // CASE 13 + bufferBase_B[n] = bufferBase_B[n-1] + PAGEWIDTH_B * NBLKY(lastmiph_Px); + yoff_Px += blockHeight_Px ? lastmiph_Px : 0; // how exactly can blockHeight be 0?? This looks wrong... + flag = n; + }else{ + // CASE 14 + bufferBase_B[n] = basestack_B[sp-1]; + if(REALWIDTH(mipw_Px) < widthstack_Px[sp-1]){ + // CASE 15 + basestack_B[sp-1] += NBLKX(mipw_Px); + widthstack_Px[sp-1] -= REALWIDTH(mipw_Px); + }else if(REALHEIGHT(miph_Px) < heightstack_Px[sp-1]){ + // CASE 16 + basestack_B[sp-1] += PAGEWIDTH_B * NBLKY(miph_Px); + heightstack_Px[sp-1] -= REALHEIGHT(miph_Px); + }else{ + // CASE 17 + sp--; + } + } + } + lastmipw_Px = mipw_Px; + lastmiph_Px = miph_Px; + } + + // Calculate position of palette. + uint32 paletteBase_B = 0; + uint64 bufwidth_Px = bufferWidth_W[nlevels-1]*64; + uint64 bufheight_Px = bufferHeight_P[nlevels-1]*pageHeight_Px; + // != means > really + if(bufwidth_Px != lastmipw_Px || bufheight_Px != lastmiph_Px){ + if(psm == PSMT8){ + // 2x2 blocks at the end of the page (even for PSMCT16S) + paletteBase_B = bufferPage_B[nlevels-1] + + ((bufwidth_Px/pageWidth_Px)*bufferHeight_P[nlevels-1] << 5) // total number of blocks + - (bufheight_Px/pageWidth_Px) * PAGEWIDTH_B // one block up + - 2; // two blocks left + }else if(psm == PSMT4){ + // One block at the end of the page + paletteBase_B = bufferPage_B[nlevels-1] + + ((bufwidth_Px/pageWidth_Px) * bufferHeight_P[nlevels-1] << 5) + - 1; + } + }else{ + if(psm == PSMT8 || psm == PSMT4){ + paletteBase_B = bufferPage_B[nlevels-1] + + (bufwidth_Px/blockWidth_Px) * (bufheight_Px/blockHeight_Px); + } + } + + uint32 bufwidth_W = bufferWidth_W[0]; + uint32 bufpage_B = bufferPage_B[0]; + uint32 pixeloff; + for(n = 0; n < nlevels; n++){ + // Calculate TRXPOS register (DSAX and DSAY, shifted up later) + // Start of buffer on current page (x in pixels, y in blocks) + pixeloff = (bufferBase_B[n] - bufpage_B) * blockWidth_Px; + // y coordinate of first pixel + yoff_Px = (pixeloff / (bufwidth_W*64)) * blockHeight_Px; + // x coordinate of first pixel + xoff_Px = pixeloff % (bufwidth_W*64); + if(bufferWidth_W[n] == bufwidth_W && + // Not quite sure what's the meaning of this. + // DSAY is 11 bits, but so is DSAX and it is not checked? + yoff_Px < 0x800){ + trxpos[n] = yoff_Px<<16 | xoff_Px; + }else{ + bufwidth_W = bufferWidth_W[n]; + bufpage_B = bufferPage_B[n]; + trxpos[n] = 0; + } + + // If using more than one page we have to swizzle rows inside page rows + if(bufwidth_W*64 / pageWidth_Px > 1){ + uint32 bufpagestride_B = bufwidth_W*64 * 32 / pageWidth_Px; // one row of pages + uint32 bufwidth_B = bufwidth_W*64 / blockWidth_Px; // one row of blocks + // To illustrate assume: + // - 8x4 block pages + // - texture is 4 pages wide + // Then the lower bits of an input block address look like: RRRPPCC + // where the C bits are the block's column inside a page + // the P bits are the block's page horizontally + // the R bits are the block's row in a row of pages + // We want to swap P and R: PPRRRCC + bufferBase_B[n] = + (bufferBase_B[n] & ~(bufpagestride_B - PAGEWIDTH_B)) // mask out R and P + | ((bufferBase_B[n] & (bufwidth_B - PAGEWIDTH_B)) * (bufpagestride_B/bufwidth_B)) // extract P and shift left + | ((bufferBase_B[n] & (bufpagestride_B - bufwidth_B)) / (bufwidth_B/PAGEWIDTH_B)); // extract R and shift right + } + + // Always have to swizzle blocks inside pages. We use a lookup, RW does bit operations + switch(psm){ + case PSMCT32: + case PSMCT24: + case PSMT8: + case PSMT8H: + case PSMT4HL: + case PSMT4HH: + // ABCDE -> CADBE + bufferBase_B[n] = bufferBase_B[n]&~0x1F | (uint64)blockmap_PSMCT32[bufferBase_B[n]&0x1F]; + break; + case PSMT4: + case PSMCT16: + // ABCDE -> ADBEC + bufferBase_B[n] = bufferBase_B[n]&~0x1F | (uint64)blockmap_PSMCT16[bufferBase_B[n]&0x1F]; + break; + case PSMCT16S: + // ABCDE -> DBAEC + bufferBase_B[n] = bufferBase_B[n]&~0x1F | (uint64)blockmap_PSMCT16S[bufferBase_B[n]&0x1F]; + break; + case PSMZ32: + case PSMZ24: + // ABCDE -> ~C~ADBE + bufferBase_B[n] = bufferBase_B[n]&~0x1F | (uint64)blockmap_PSMZ32[bufferBase_B[n]&0x1F]; + break; + case PSMZ16: + // ABCDE -> ~A~DBEC + bufferBase_B[n] = bufferBase_B[n]&~0x1F | (uint64)blockmap_PSMZ16[bufferBase_B[n]&0x1F]; + break; + case PSMZ16S: + // ABCDE -> ~D~BAEC + bufferBase_B[n] = bufferBase_B[n]&~0x1F | (uint64)blockmap_PSMZ16S[bufferBase_B[n]&0x1F]; + break; + default: break; + } + } + + // Same dance as above, with the palette + if(bufwidth_W*64 / pageWidth_Px > 1){ + uint32 bufpagestride_B = bufwidth_W*64 * 32 / pageWidth_Px; // one row of pages + uint32 bufwidth_B = bufwidth_W*64 / blockWidth_Px; // one row of blocks + paletteBase_B = + (paletteBase_B & ~(bufpagestride_B - PAGEWIDTH_B)) // mask out R and P + | ((paletteBase_B & (bufwidth_B - PAGEWIDTH_B)) * (bufpagestride_B/bufwidth_B)) // extract P and shift left + | ((paletteBase_B & (bufpagestride_B - bufwidth_B)) / (bufwidth_B/PAGEWIDTH_B)); // extract R and shift right + } + switch(psm){ + case PSMCT32: + case PSMCT24: + case PSMT8: + case PSMT8H: + case PSMT4HL: + case PSMT4HH: + paletteBase_B = paletteBase_B&~0x1F | (uint64)blockmap_PSMCT32[paletteBase_B&0x1F]; + break; + case PSMT4: + case PSMCT16: + paletteBase_B = paletteBase_B&~0x1F | (uint64)blockmap_PSMCT16[paletteBase_B&0x1F]; + break; + case PSMCT16S: + paletteBase_B = paletteBase_B&~0x1F | (uint64)blockmap_PSMCT16S[paletteBase_B&0x1F]; + break; + case PSMZ32: + case PSMZ24: + paletteBase_B = paletteBase_B&~0x1F | (uint64)blockmap_PSMZ32[paletteBase_B&0x1F]; + break; + case PSMZ16: + paletteBase_B = paletteBase_B&~0x1F | (uint64)blockmap_PSMZ16[paletteBase_B&0x1F]; + break; + case PSMZ16S: + paletteBase_B = paletteBase_B&~0x1F | (uint64)blockmap_PSMZ16S[paletteBase_B&0x1F]; + break; + default: break; + } + *paletteBase = paletteBase_B; + *totalSize = bufferPage_B[nlevels-1] + // start of last buffer` + bufferWidth_W[nlevels-1]*64/blockWidth_Px * // number of horizontal blocks in last level + pageHeight_Px*bufferHeight_P[nlevels-1]/blockHeight_Px; // number of vertical blocks in last level + *totalSize *= 64; // to words + +#undef BLKSTRIDE +#undef NBLKX +#undef NBLKY +#undef NPGX +#undef NPGY +#undef REALWIDTH +#undef REALHEIGHT +} + +static void +createTexRaster(Raster *raster) +{ + // We use a map for fast lookup, even for impossible depths + static int32 pageWidths[32] = { + 128, 128, 128, 128, + 128, 128, 128, 128, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + }; + static int32 pageHeights[32] = { + 128, 128, 128, 128, + 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, + }; enum { TCC_RGBA = 1 << 2, CLD_1 = 1 << 29, - }; - uint64 bufferWidth[7], bufferBase[7]; - int32 pageWidth, pageHeight; - Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset); + WD2BLK = 64, // words per block + WD2PG = 2048, // words per page + }; + int32 pixelformat, palformat; + // TEX0 fields (not all) + int64 tbw = 0; // texture buffer width, texels/64 + int64 psm = 0; // pixel storage mode + int64 tw = 0; // texture width exponent, width = 2^tw + int64 th = 0; // texture height exponent, height = 2^th + int64 tcc = 0; // texture color component, 0 = rgb, 1 = rgba + int64 cpsm = 0; // CLUT pixel storage mode + int64 cld = 0; // CLUT buffer load control + + uint64 bufferWidth[7]; // in number of pixels / 64 + uint64 bufferBase[7]; // block address + uint32 trxpos_hi[8]; + int32 width, height, depth; + int32 pageWidth, pageHeight; + int32 paletteWidth, paletteHeight, paletteDepth; + int32 palettePagewidth, palettePageheight; + + + Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset); + pixelformat = raster->format & 0xF00; + palformat = raster->format & 0x6000; + width = raster->width; + height = raster->height; + depth = raster->depth; + + + // RW doesn't seem to check this, hm... if(raster->flags & Raster::DONTALLOCATE) return; //printf("%x %x %x %x\n", raster->format, raster->flags, raster->type, noNewStyleRasters); - assert(raster->type == Raster::TEXTURE); - switch(raster->depth){ - case 4: - pageWidth = 128; - pageHeight = 128; - break; - case 8: - pageWidth = 128; - pageHeight = 64; - break; - case 16: - pageWidth = 64; - pageHeight = 64; - break; - case 32: - pageWidth = 64; - pageHeight = 32; - break; - default: - assert(0 && "unsupported depth"); - } - int32 logw = 0, logh = 0; + pageWidth = pageWidths[depth-1]; + pageHeight = pageHeights[depth-1]; + int32 s; - for(s = 1; s < raster->width; s *= 2) - logw++; - for(s = 1; s < raster->height; s *= 2) - logh++; - ras->kl = 0xFC0; + tw = 0; + for(s = 1; s < width; s *= 2) + tw++; + th = 0; + for(s = 1; s < height; s *= 2) + th++; + ras->kl = defaultMipMapKL; + // unk2[0] = 1 //printf("%d %d %d %d\n", raster->width, logw, raster->height, logh); // round up to page width, set TBW, TW, TH - ras->tex0[0] |= (raster->width < pageWidth ? pageWidth : raster->width)/64 << 14; - ras->tex0[0] |= logw << 26; - ras->tex0[0] |= logh << 30; - ras->tex0[1] |= logh >> 2; + tbw = max(width,pageWidth)/64; // set PSM, TCC, CLD, CPSM and figure out palette format - int32 paletteWidth, paletteHeight, paletteDepth; - int32 palettePagewidth, palettePageheight; - if(raster->format & (Raster::PAL4 | Raster::PAL8)) - switch(raster->format & 0xF00){ - case Raster::C1555: - ras->tex0[1] |= PSMCT16S << 19; + if(palformat){ + if(palformat == Raster::PAL8){ + psm = PSMT8; + paletteWidth = 16; + paletteHeight = 16; + }else if(palformat == Raster::PAL4){ + psm = PSMT4; + paletteWidth = 8; + paletteHeight = 2; + }else{ + // can't happen, sanity check in getRasterFormat + return; + } + tcc = 1; // RGBA + cld = 1; + if(pixelformat == Raster::C1555){ paletteDepth = 2; - palettePagewidth = palettePageheight = 64; - break; - case Raster::C8888: - ras->tex0[1] |= PSMCT32 << 19; + cpsm = PSMCT16S; + palettePagewidth = 64; + palettePageheight = 64; + }else if(pixelformat == Raster::C8888){ paletteDepth = 4; + cpsm = PSMCT32; palettePagewidth = 64; palettePageheight = 32; - break; - default: - assert(0 && "unsupported palette format\n"); - } - if(raster->format & Raster::PAL4){ - ras->tex0[0] |= PSMT4 << 20; - ras->tex0[1] |= CLD_1 | TCC_RGBA; - paletteWidth = 8; - paletteHeight = 2; - }else if(raster->format & Raster::PAL8){ - ras->tex0[0] |= PSMT8 << 20; - ras->tex0[1] |= CLD_1 | TCC_RGBA; - paletteWidth = paletteHeight = 16; + }else + // can't happen, sanity check in getRasterFormat + return; }else{ paletteWidth = 0; paletteHeight = 0; paletteDepth = 0; palettePagewidth = 0; palettePageheight = 0; - switch(raster->format & 0xF00){ - case Raster::C1555: - ras->tex0[0] |= PSMCT16S << 20; - ras->tex0[1] |= TCC_RGBA; - break; - case Raster::C8888: - ras->tex0[0] |= PSMCT32 << 20; - ras->tex0[1] |= TCC_RGBA; - break; - case Raster::C888: - ras->tex0[0] |= PSMCT24 << 20; - break; - default: - assert(0 && "unsupported raster format\n"); - } + if(pixelformat == Raster::C8888){ + psm = PSMCT32; + tcc = 1; // RGBA + }else if(pixelformat == Raster::C888){ + psm = PSMCT24; + tcc = 0; // RGB + }else if(pixelformat == Raster::C1555){ + psm = PSMCT16S; + tcc = 1; // RGBA + }else + // can't happen, sanity check in getRasterFormat + return; } for(int i = 0; i < 7; i++){ @@ -203,142 +875,214 @@ rasterCreate(Raster *raster) } int32 mipw, miph; + int32 w, h; int32 n; int32 nPagW, nPagH; - int32 w = raster->width; - int32 h = raster->height; - int32 d = raster->depth; - raster->stride = w*d/8; + raster->stride = width*depth/8; if(raster->format & Raster::MIPMAP){ + // NOTE: much of this code seems to be totally useless. + // calcOffsets overwrites what we calculate here. I wonder + // why this code even is in RW. Maybe it's older code that used + // the GS' automatic base pointer calculation? + + // see the left columns in the maps above static uint32 blockOffset32_24_8[8] = { 0, 2, 2, 8, 8, 10, 10, 32 }; static uint32 blockOffset16_4[8] = { 0, 1, 4, 5, 16, 17, 20, 21 }; static uint32 blockOffset16S[8] = { 0, 1, 8, 9, 4, 5, 12, 13 }; uint64 lastBufferWidth; - mipw = w; - miph = h; - lastBufferWidth = max(pageWidth, w)/64; - ras->texelSize = 0; - int32 gsoffset = 0; - int32 gsaddress = 0; - for(n = 0; n < 7; n++){ - if(w >= 8 && h >= 8 && (mipw < 8 || miph < 8)) + mipw = width; + miph = height; + lastBufferWidth = max(pageWidth, width)/64; + ras->pixelSize = 0; + int32 lastaddress = 0; // word address + int32 nextaddress = 0; // word address + int32 stride; // in bytes + for(n = 0; mipw != 0 && miph != 0 && n < maxMipLevels; n++){ + if(width >= 8 && height >= 8 && (mipw < 8 || miph < 8)) break; - ras->texelSize += ALIGN64(mipw*miph*d/8); + ras->pixelSize += ALIGN64(mipw*miph*depth/8); bufferWidth[n] = max(pageWidth, mipw)/64; + stride = bufferWidth[n]*64*depth/8; + // If buffer width changes, align next address to page if(bufferWidth[n] != lastBufferWidth){ - nPagW = ((w >> n-1) + pageWidth-1)/pageWidth; - nPagH = ((h >> n-1) + pageHeight-1)/pageHeight; - gsaddress = (gsoffset + nPagW*nPagH*0x800) & ~0x7FF; + nPagW = ((width >> n-1) + pageWidth-1)/pageWidth; + nPagH = ((height >> n-1) + pageHeight-1)/pageHeight; + nextaddress = (lastaddress + nPagW*nPagH*WD2PG) & ~(WD2PG-1); } lastBufferWidth = bufferWidth[n]; - gsaddress = ALIGN64(gsaddress); - uint32 b = gsaddress/256 & 7; - switch(ras->tex0[0]>>20 & 0x3F){ - case 0: case 1: case 0x13: + nextaddress = ALIGN64(nextaddress); // this should already be the case... + uint32 b = nextaddress>>(11-3) & 7; // upper three bits of block-in-page address + switch(psm){ + case PSMCT32: + case PSMCT24: + case PSMT8: b = blockOffset32_24_8[b]; break; - case 2: case 0x14: + case PSMCT16: + case PSMT4: b = blockOffset16_4[b]; break; - case 0xA: + case PSMCT16S: b = blockOffset16S[b]; break; default: // can't happen break; } - bufferBase[n] = b + (gsaddress>>11 << 5); - int32 stride = bufferWidth[n]/64*d/8; - gsaddress = ALIGN64(miph*stride/4 + gsoffset); + // shift to page address, then to block address and add offset inside page + bufferBase[n] = b + (nextaddress>>11 << 5); + + lastaddress = nextaddress; + nextaddress = ALIGN64(miph*stride/4 + lastaddress); mipw /= 2; miph /= 2; } - assert(0); + + // Do the real work here + uint32 paletteBase; + uint32 totalSize; + calcOffsets(width, height, psm, bufferBase, bufferWidth, trxpos_hi, &totalSize, &paletteBase); + + ras->paletteSize = paletteWidth*paletteHeight*paletteDepth; + ras->miptbp1 = + bufferWidth[1]<<14 | (bufferBase[1] & 0x3FFF)<<0 + | bufferWidth[2]<<34 | (bufferBase[2] & 0x3FFF)<<20 + | bufferWidth[3]<<54 | (bufferBase[3] & 0x3FFF)<<40; + ras->miptbp2 = + bufferWidth[4]<<14 | (bufferBase[4] & 0x3FFF)<<0 + | bufferWidth[5]<<34 | (bufferBase[5] & 0x3FFF)<<20 + | bufferWidth[6]<<54 | (bufferBase[6] & 0x3FFF)<<40; + ras->tex1low = (n-1)<<2; + ras->totalSize = totalSize; + if(ras->paletteSize){ + ras->paletteBase = paletteBase; + if(ras->paletteBase*64 == ras->totalSize) + ras->totalSize += WD2PG; + }else + ras->paletteBase = 0; }else{ // No mipmaps - ras->texelSize = ALIGN16(raster->stride*raster->height); + ras->pixelSize = ALIGN16(raster->stride*raster->height); ras->paletteSize = paletteWidth*paletteHeight*paletteDepth; - ras->miptbp1[0] |= 1<<14; // TBW1 - ras->miptbp1[1] |= 1<<2 | 1<<22; // TBW2,3 - ras->miptbp2[0] |= 1<<14; // TBW4 - ras->miptbp2[1] |= 1<<2 | 1<<22; // TBW5,6 + ras->miptbp1 = 1<<54 | 1<<34 | 1<<14; + ras->miptbp2 = 1<<54 | 1<<34 | 1<<14; ras->tex1low = 0; // one mipmap level // find out number of pages needed - nPagW = (raster->width + pageWidth-1)/pageWidth; - nPagH = (raster->height + pageHeight-1)/pageHeight; + nPagW = (width + pageWidth-1)/pageWidth; + nPagH = (height + pageHeight-1)/pageHeight; // calculate buffer width in units of pixels/64 bufferBase[0] = 0; bufferWidth[0] = nPagW*pageWidth / 64; // calculate whole buffer size in words - ras->gsSize = nPagW*nPagH*0x800; + ras->totalSize = nPagW*nPagH*WD2PG; // calculate palette offset on GS in units of words/64 if(ras->paletteSize){ - // Maximum palette size will be 256 words. + // Maximum palette size is 256 words. // If there is still room, use it! - // TODO: find out why this check works - if(pageWidth*nPagW > raster->width || - pageHeight*nPagH > raster->height) - ras->paletteOffset = (ras->gsSize - 256)/ 64; + // If dimensions don't fill a page, we have at least + // half a page left, enough for any palette + if(pageWidth*nPagW > width || + pageHeight*nPagH > height) + ras->paletteBase = (ras->totalSize - 256) / WD2BLK; else{ // Otherwise allocate more space... - ras->paletteOffset = ras->gsSize / 64; - // ...using the same calculation as above + ras->paletteBase = ras->totalSize / WD2BLK; + // ...using the same calculation as above. + // WHY? we never need more than one page! nPagW = (paletteWidth + palettePagewidth-1)/palettePagewidth; nPagH = (paletteHeight + palettePageheight-1)/palettePageheight; - ras->gsSize += nPagW*nPagH*0x800; + ras->totalSize += nPagW*nPagH*WD2PG; } }else - ras->paletteOffset = 0; + ras->paletteBase = 0; } + ras->tex0 = tbw << 14 | + psm << 20 | + tw << 26 | + th << 30 | + tcc << 34 | + cpsm << 51 | + 0 << 55 | // csm0 + 0 << 56 | // entry offset + cld << 61; + + // allocate data and fill with GIF packets - ras->texelSize = ALIGN16(ras->texelSize); + ras->pixelSize = ALIGN16(ras->pixelSize); int32 numLevels = MAXLEVEL(ras)+1; // No GIF packet because we either don't want it (pre 0x310 rasters) // or the data wouldn't fit into a DMA packet if(noNewStyleRasters || (raster->width*raster->height*raster->depth/8/0x10) >= 0x7FFF){ - ras->dataSize = ras->paletteSize+ras->texelSize; + ras->dataSize = ras->paletteSize+ras->pixelSize; uint8 *data = (uint8*)mallocalign(ras->dataSize, 0x40); + assert(data); ras->data = data; - raster->texels = data; + raster->pixels = data; if(ras->paletteSize) - raster->palette = data + ras->texelSize; + raster->palette = data + ras->pixelSize; if(raster->depth == 8) ras->flags |= Ps2Raster::SWIZZLED8; }else{ - ras->flags |= Ps2Raster::HASGIFPACKETS; - int32 psm = ras->tex0[0]>>20 & 0x3F; - //int32 cpsm = ras->tex0[1]>>19 & 0x3F; + ras->flags |= Ps2Raster::NEWSTYLE; + uint64 paltrxpos = 0; + uint32 dsax = trxpos_hi[numLevels-1] & 0x7FF; + uint32 dsay = trxpos_hi[numLevels-1]>>16 & 0x7FF; + // Set swizzle flags and calculate TRXPOS for palette if(psm == PSMT8){ ras->flags |= Ps2Raster::SWIZZLED8; - // TODO: crazy stuff + if(cpsm == PSMCT32 && bufferWidth[numLevels-1] == 2){ // one page + // unswizzle the starting block of the last buffer and palette + uint32 bufbase_B = bufferBase[numLevels-1]&~0x1F | (uint64)blockmaprev_PSMCT32[bufferBase[numLevels-1]&0x1F]; + uint32 palbase_B = ras->paletteBase&~0x1F | (uint64)blockmaprev_PSMCT32[ras->paletteBase&0x1F]; + // find start of page of last level (16,16 are PSMT8 block dimensions) + uint32 page_B = bufbase_B - 8*(dsay/16) - dsax/16; + // find palette DSAX/Y (in PSMCT32!) + dsay = (palbase_B - page_B)/8 * 8; // block/blocksPerPageX * blockHeight + dsax = (palbase_B - page_B)*8 % 64; // block*blockWidth % pageWidth + if(dsay < 0x800) + paltrxpos = dsay<<16 | dsax; + } } if(psm == PSMT4){ - // swizzle flag probably depends on version :/ + // swizzle flag depends on version :/ // but which version? .... - if(rw::version > 0x31000) + if(rw::version > 0x31000){ ras->flags |= Ps2Raster::SWIZZLED4; - // TODO: crazy stuff + // Where can this come from? if anything we're using PSMCT16S + if(cpsm == PSMCT16){ + // unswizzle the starting block of the last buffer and palette + uint32 bufbase_B = bufferBase[numLevels-1]&~0x1F | (uint64)blockmaprev_PSMCT16[bufferBase[numLevels-1]&0x1F]; + uint32 palbase_B = ras->paletteBase&~0x1F | (uint64)blockmaprev_PSMCT16[ras->paletteBase&0x1F]; + // find start of page of last level (32,16 are PSMT4 block dimensions) + uint32 page_B = bufbase_B - 4*(dsay/32) - dsax/16; + // find palette DSAX/Y (in PSMCT16!) + dsay = (palbase_B - page_B)/4 * 8; // block/blocksPerPageX * blockHeight + dsax = (palbase_B - page_B)*16 % 128; // block*blockWidth % pageWidth + if(dsay < 0x800) + paltrxpos = dsay<<16 | dsax; + } + } } - ras->texelSize = 0x50*numLevels; // GIF packets + ras->pixelSize = 0x50*numLevels; // GIF packets int32 minW, minH; - ps2MinSize(psm, ras->flags, &minW, &minH); + transferMinSize(psm, ras->flags, &minW, &minH); w = raster->width; h = raster->height; n = numLevels; while(n--){ - mipw = w < minW ? minW : w; - miph = h < minH ? minH : h; - ras->texelSize += ALIGN16(mipw*miph*raster->depth/8); + mipw = max(w, minW); + miph = max(h, minH); + ras->pixelSize += ALIGN16(mipw*miph*raster->depth/8); w /= 2; h /= 2; } @@ -348,25 +1092,44 @@ rasterCreate(Raster *raster) ras->paletteSize = 0x50 + paletteDepth*paletteWidth*paletteHeight; } - // TODO: allocate space for more DMA packets - // every upload as 4 qwords: + // One transfer per buffer width, 4 qwords: // DMAcnt(2) [NOP, DIRECT] // GIF tag A+D // BITBLTBUF // DMAref(pixel data) [NOP, DIRECT] - ras->dataSize = ras->paletteSize+ras->texelSize; + uint32 extrasize = 0x10; // PixelPtr + int32 numTransfers = 0; + for(n = 0; n < numLevels; n++) + if(trxpos_hi[n] == 0){ + extrasize += 0x40; + numTransfers++; + } + if(ras->paletteSize){ + extrasize += 0x40; + numTransfers++; + } + // What happens here? + if(ras->paletteSize && paltrxpos == 0) + ras->dataSize = ALIGN(ras->pixelSize,128) + ALIGN(ras->paletteSize,64) + extrasize + 0x70; + else + ras->dataSize = ALIGN(ras->paletteSize+ras->pixelSize,64) + extrasize + 0x70; uint8 *data = (uint8*)mallocalign(ras->dataSize, 0x40); + uint32 *xferchain = (uint32*)(data + 0x10); assert(data); ras->data = data; - raster->texels = data + 0x50; + Ps2Raster::PixelPtr *pp = (Ps2Raster::PixelPtr*)data; + pp->numTransfers = numTransfers; + pp->numTotalTransfers = numTransfers; + pp->pixels = (uint8*)ALIGN((uintptr)data + extrasize, 128); + raster->pixels = (uint8*)pp; if(ras->paletteSize) - raster->palette = data + ras->texelSize + 0x50; - uint32 *p = (uint32*)data; + raster->palette = pp->pixels + ALIGN(ras->pixelSize, 128) + 0x50; + uint32 *p = (uint32*)pp->pixels; w = raster->width; h = raster->height; for(n = 0; n < numLevels; n++){ - mipw = w < minW ? minW : w; - miph = h < minH ? minH : h; + mipw = max(w, minW); + miph = max(h, minH); // GIF tag *p++ = 3; // NLOOP = 3 @@ -375,8 +1138,14 @@ rasterCreate(Raster *raster) *p++ = 0; // TRXPOS - *p++ = 0; // TODO - *p++ = 0; // TODO + if(ras->flags & Ps2Raster::SWIZZLED8 && psm == PSMT8 || + ras->flags & Ps2Raster::SWIZZLED4 && psm == PSMT4){ + *p++ = 0; // SSAX/Y is always 0 + *p++ = (trxpos_hi[n] & ~0x10001)/2; // divide both DSAX/Y by 2 + }else{ + *p++ = 0; + *p++ = trxpos_hi[n]; + } *p++ = 0x51; *p++ = 0; @@ -399,18 +1168,62 @@ rasterCreate(Raster *raster) *p++ = 0; // GIF tag - uint32 sz = mipw*miph*raster->depth/8 + 0xF >> 4; - *p++ = sz; + uint32 sz = ALIGN16(mipw*miph*raster->depth/8)/16; + *p++ = sz & 0x7FFF; *p++ = 0x08000000; // IMAGE *p++ = 0; *p++ = 0; + if(trxpos_hi[n] == 0){ + // Add a transfer, see above for layout + + *xferchain++ = 0x10000002; // DMAcnt, 2 qwords + *xferchain++ = 0; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000002; // VIF DIRECT 2 qwords + + // GIF tag + *xferchain++ = 1; // NLOOP = 1 + *xferchain++ = 0x10000000; // NREG = 1 + *xferchain++ = 0xE; // A+D + *xferchain++ = 0; + + // BITBLTBUF + if(ras->flags & Ps2Raster::SWIZZLED8 && psm == PSMT8){ + // PSMT8 is swizzled to PSMCT32 and dimensions are halved + *xferchain++ = PSMCT32<<24 | bufferWidth[n]/2<<16; // src buffer + *xferchain++ = PSMCT32<<24 | bufferWidth[n]/2<<16 | bufferBase[n]; // dst buffer + }else if(ras->flags & Ps2Raster::SWIZZLED4 && psm == PSMT4){ + // PSMT4 is swizzled to PSMCT16 and dimensions are halved + *xferchain++ = PSMCT16<<24 | bufferWidth[n]/2<<16; // src buffer + *xferchain++ = PSMCT16<<24 | bufferWidth[n]/2<<16 | bufferBase[n]; // dst buffer + }else{ + *xferchain++ = psm<<24 | bufferWidth[n]<<16; // src buffer + *xferchain++ = psm<<24 | bufferWidth[n]<<16 | bufferBase[n]; // dst buffer + } + *xferchain++ = 0x50; + *xferchain++ = 0; + + *xferchain++ = 0x30000000 | sz+5; // DMAref + // this obviously only works with 32 bit pointers, but it's only needed on the PS2 anyway + *xferchain++ = (uint32)(uintptr)p - 0x50; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000000 | sz+5; // VIF DIRECT 2 qwords + }else{ + // Add to existing transfer + xferchain[-4] = 0x30000000 | (xferchain[-4]&0xFFFF) + sz+5; // last DMAref + xferchain[-1] = 0x50000000 | (xferchain[-1]&0xFFFF) + sz+5; // last DIRECT + } + p += sz*4; w /= 2; h /= 2; } if(ras->paletteSize){ + // huh? + if(paltrxpos) + raster->palette = (uint8*)p + 0x50; p = (uint32*)(raster->palette - 0x50); // GIF tag *p++ = 3; // NLOOP = 3 @@ -419,8 +1232,8 @@ rasterCreate(Raster *raster) *p++ = 0; // TRXPOS - *p++ = 0; // TODO - *p++ = 0; // TODO + *(uint64*)p = paltrxpos; + p += 2; *p++ = 0x51; *p++ = 0; @@ -437,13 +1250,98 @@ rasterCreate(Raster *raster) *p++ = 0; // GIF tag - uint32 sz = ras->paletteSize - 0x50 + 0xF >> 4; - *p++ = sz; + uint32 sz = ALIGN16(ras->paletteSize - 0x50)/16; + *p++ = sz & 0x7FFF; *p++ = 0x08000000; // IMAGE *p++ = 0; *p++ = 0; + + // Transfer + *xferchain++ = 0x10000002; // DMAcnt, 2 qwords + *xferchain++ = 0; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000002; // VIF DIRECT 2 qwords + + // GIF tag + *xferchain++ = 1; // NLOOP = 1 + *xferchain++ = 0x10000000; // NREG = 1 + *xferchain++ = 0xE; // A+D + *xferchain++ = 0; + + // BITBLTBUF + if(paltrxpos == 0){ + *xferchain++ = cpsm<<24 | 1<<16; // src buffer + *xferchain++ = cpsm<<24 | 1<<16 | ras->paletteBase; // dst buffer + *xferchain++ = 0x50; + *xferchain++ = 0; + }else{ + // copy last pixel bitbltbuf...if uploading palette separately it's still the same buffer + xferchain[0] = xferchain[-16]; + xferchain[1] = xferchain[-15]; + xferchain[2] = xferchain[-14]; + xferchain[3] = xferchain[-13]; + // Add to last transfer + xferchain[-16] = 0x30000000 | (xferchain[-16]&0xFFFF) + sz+5; // last DMAref + xferchain[-13] = 0x50000000 | (xferchain[-13]&0xFFFF) + sz+5; // last DIRECT + xferchain += 4; + pp->numTransfers--; + } + + *xferchain++ = 0x30000000 | sz+5; // DMAref + // this obviously only works with 32 bit pointers, but it's only needed on the PS2 anyway + *xferchain++ = (uint32)(uintptr)p - 0x50; + *xferchain++ = 0; // VIF nop + *xferchain++ = 0x50000000 | sz+5; // VIF DIRECT 2 qwords } } + raster->originalPixels = raster->pixels; + raster->originalStride = raster->stride; + if(ras->flags & Ps2Raster::NEWSTYLE) + raster->pixels = ((Ps2Raster::PixelPtr*)raster->pixels)->pixels + 0x50; +} + +void +rasterCreate(Raster *raster) +{ + if(!getRasterFormat(raster)) + return; + + // init raster + raster->pixels = nil; + raster->palette = nil; + raster->originalWidth = raster->width; + raster->originalHeight = raster->height; + raster->originalPixels = raster->pixels; + if(raster->width == 0 || raster->height == 0){ + raster->flags = Raster::DONTALLOCATE; + raster->stride = 0; + raster->originalStride = 0; + return; + } + + switch(raster->type){ + case Raster::NORMAL: + // TODO + break; + case Raster::ZBUFFER: + // TODO. only RW_PS2 + // get info from video mode + raster->flags = Raster::DONTALLOCATE; + break; + case Raster::CAMERA: + // TODO. only RW_PS2 + // get info from video mode + raster->flags = Raster::DONTALLOCATE; + break; + case Raster::TEXTURE: + createTexRaster(raster); + break; + case Raster::CAMERATEXTURE: + // TODO. only RW_PS2 + // check wdith/height and fall through to texture + break; + } + } uint8* @@ -467,7 +1365,7 @@ int32 rasterNumLevels(Raster *raster) { Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, raster, nativeRasterOffset); - if(raster->texels == nil) return 0; + if(raster->pixels == nil) return 0; if(raster->format & Raster::MIPMAP) return MAXLEVEL(ras)+1; return 1; @@ -477,19 +1375,16 @@ static void* createNativeRaster(void *object, int32 offset, int32) { Ps2Raster *raster = PLUGINOFFSET(Ps2Raster, object, offset); - raster->tex0[0] = 0; - raster->tex0[1] = 0; - raster->paletteOffset = 0; + raster->tex0 = 0; + raster->paletteBase = 0; raster->kl = 0xFC0; raster->tex1low = 0; raster->unk2 = 0; - raster->miptbp1[0] = 0; - raster->miptbp1[1] = 0; - raster->miptbp2[0] = 0; - raster->miptbp2[1] = 0; - raster->texelSize = 0; + raster->miptbp1 = 0; + raster->miptbp2 = 0; + raster->pixelSize = 0; raster->paletteSize = 0; - raster->gsSize = 0; + raster->totalSize = 0; raster->flags = 0; raster->dataSize = 0; @@ -559,7 +1454,7 @@ registerNativeRaster(void) void printTEX0(uint64 tex0) { - printf("%016lX ", tex0); + printf("%016llX ", tex0); uint32 tbp0 = tex0 & 0x3FFF; tex0 >>= 14; uint32 tbw = tex0 & 0x3F; tex0 >>= 6; uint32 psm = tex0 & 0x3F; tex0 >>= 6; @@ -579,7 +1474,7 @@ printTEX0(uint64 tex0) void printTEX1(uint64 tex1) { - printf("%016lX ", tex1); + printf("%016llX ", tex1); uint32 lcm = tex1 & 0x1; tex1 >>= 2; uint32 mxl = tex1 & 0x7; tex1 >>= 3; uint32 mmag = tex1 & 0x1; tex1 >>= 1; @@ -644,14 +1539,14 @@ struct StreamRasterExt int32 depth; uint16 rasterFormat; int16 type; - uint32 tex0[2]; + uint64 tex0; uint32 paletteOffset; uint32 tex1low; - uint32 miptbp1[2]; - uint32 miptbp2[2]; - uint32 texelSize; + uint64 miptbp1; + uint64 miptbp2; + uint32 pixelSize; uint32 paletteSize; - uint32 gsSize; + uint32 totalSize; uint32 mipmapVal; }; @@ -700,23 +1595,20 @@ readNativeTexture(Stream *stream) goto fail; } stream->read(&streamExt, 0x40); -printf("%X %X %X %X %X %08X%08X %X %X %08X%08X %08X%08X %X %X %X %X\n", +printf("%X %X %X %X %X %016llX %X %X %016llX %016llX %X %X %X %X\n", streamExt.width, streamExt.height, streamExt.depth, streamExt.rasterFormat, streamExt.type, -streamExt.tex0[1], -streamExt.tex0[0], +streamExt.tex0, streamExt.paletteOffset, streamExt.tex1low, -streamExt.miptbp1[1], -streamExt.miptbp1[0], -streamExt.miptbp2[1], -streamExt.miptbp2[0], -streamExt.texelSize, +streamExt.miptbp1, +streamExt.miptbp2, +streamExt.pixelSize, streamExt.paletteSize, -streamExt.gsSize, +streamExt.totalSize, streamExt.mipmapVal); noNewStyleRasters = streamExt.type < 2; @@ -737,17 +1629,14 @@ streamExt.mipmapVal); calcTEX1(raster, &tex1, tex->filterAddressing & 0xF); // printTEX1(tex1); - natras->tex0[0] = streamExt.tex0[0]; - natras->tex0[1] = streamExt.tex0[1]; - natras->paletteOffset = streamExt.paletteOffset; + natras->tex0 = streamExt.tex0; + natras->paletteBase = streamExt.paletteOffset; natras->tex1low = streamExt.tex1low; - natras->miptbp1[0] = streamExt.miptbp1[0]; - natras->miptbp1[1] = streamExt.miptbp1[1]; - natras->miptbp2[0] = streamExt.miptbp2[0]; - natras->miptbp2[1] = streamExt.miptbp2[1]; - natras->texelSize = streamExt.texelSize; + natras->miptbp1 = streamExt.miptbp1; + natras->miptbp2 = streamExt.miptbp2; + natras->pixelSize = streamExt.pixelSize; natras->paletteSize = streamExt.paletteSize; - natras->gsSize = streamExt.gsSize; + natras->totalSize = streamExt.totalSize; natras->kl = streamExt.mipmapVal; //printf("%X %X\n", natras->paletteOffset, natras->tex1low); // printf("%08X%08X %08X%08X %08X%08X\n", @@ -762,9 +1651,9 @@ streamExt.mipmapVal); goto fail; } if(streamExt.type < 2){ - stream->read(raster->texels, length); + stream->read(raster->pixels, length); }else{ - stream->read(raster->texels-0x50, natras->texelSize); + stream->read(((Ps2Raster::PixelPtr*)raster->originalPixels)->pixels, natras->pixelSize); stream->read(raster->palette-0x50, natras->paletteSize); } //printf("\n"); @@ -790,7 +1679,7 @@ writeNativeTexture(Texture *tex, Stream *stream) writeChunkHeader(stream, ID_STRING, len); stream->write(tex->mask, len); - int32 sz = ras->texelSize + ras->paletteSize; + int32 sz = ras->pixelSize + ras->paletteSize; writeChunkHeader(stream, ID_STRUCT, 12 + 64 + 12 + sz); writeChunkHeader(stream, ID_STRUCT, 64); StreamRasterExt streamExt; @@ -801,27 +1690,24 @@ writeNativeTexture(Texture *tex, Stream *stream) streamExt.type = 0; if(ras->flags == Ps2Raster::SWIZZLED8 && raster->depth == 8) streamExt.type = 1; - if(ras->flags & Ps2Raster::HASGIFPACKETS) + if(ras->flags & Ps2Raster::NEWSTYLE) streamExt.type = 2; - streamExt.tex0[0] = ras->tex0[0]; - streamExt.tex0[1] = ras->tex0[1]; - streamExt.paletteOffset = ras->paletteOffset; + streamExt.tex0 = ras->tex0; + streamExt.paletteOffset = ras->paletteBase; streamExt.tex1low = ras->tex1low; - streamExt.miptbp1[0] = ras->miptbp1[0]; - streamExt.miptbp1[1] = ras->miptbp1[1]; - streamExt.miptbp2[0] = ras->miptbp2[0]; - streamExt.miptbp2[1] = ras->miptbp2[1]; - streamExt.texelSize = ras->texelSize; + streamExt.miptbp1 = ras->miptbp1; + streamExt.miptbp2 = ras->miptbp2; + streamExt.pixelSize = ras->pixelSize; streamExt.paletteSize = ras->paletteSize; - streamExt.gsSize = ras->gsSize; + streamExt.totalSize = ras->totalSize; streamExt.mipmapVal = ras->kl; stream->write(&streamExt, 64); writeChunkHeader(stream, ID_STRUCT, sz); if(streamExt.type < 2){ - stream->write(raster->texels, sz); + stream->write(raster->pixels, sz); }else{ - stream->write(raster->texels-0x50, ras->texelSize); + stream->write(((Ps2Raster::PixelPtr*)raster->originalPixels)->pixels, ras->pixelSize); stream->write(raster->palette-0x50, ras->paletteSize); } } @@ -835,7 +1721,7 @@ getSizeNativeTexture(Texture *tex) size += 12; size += 12 + 64; Ps2Raster *ras = PLUGINOFFSET(Ps2Raster, tex->raster, nativeRasterOffset); - size += 12 + ras->texelSize + ras->paletteSize; + size += 12 + ras->pixelSize + ras->paletteSize; return size; } diff --git a/src/ps2/ps2skin.cpp b/src/ps2/ps2skin.cpp index f605fa3..36609b4 100644 --- a/src/ps2/ps2skin.cpp +++ b/src/ps2/ps2skin.cpp @@ -74,7 +74,7 @@ readNativeSkin(Stream *stream, int32, void *object, int32 offset) Geometry *geometry = (Geometry*)object; uint32 platform; if(!findChunk(stream, ID_STRUCT, nil, nil)){ - RWERROR((ERR_CHUNK, "STRUCT")) + RWERROR((ERR_CHUNK, "STRUCT")); return nil; } platform = stream->readU32(); diff --git a/src/ps2/rwps2.h b/src/ps2/rwps2.h old mode 100644 new mode 100755 index 9a2d930..f98f4a2 --- a/src/ps2/rwps2.h +++ b/src/ps2/rwps2.h @@ -1,15 +1,19 @@ namespace rw { + +#ifdef RW_PS2 +struct EngineStartParams +{ +}; +#endif + namespace ps2 { void initializePlatform(void); +extern Device renderdevice; + struct InstanceData { - // 0 - addresses in ref tags need fixing - // 1 - no ref tags, so no fixing - // set by the program: - // 2 - ref tags are fixed, need to unfix before stream write - uint32 arePointersFixed; uint32 dataSize; uint8 *data; Material *material; @@ -57,10 +61,8 @@ void registerNativeDataPlugin(void); void printDMA(InstanceData *inst); void sizedebug(InstanceData *inst); -// only RW_PS2 -void fixDmaOffsets(InstanceData *inst); -void unfixDmaOffsets(InstanceData *inst); -// +void fixDmaOffsets(InstanceData *inst); // only RW_PS2 +int32 unfixDmaOffsets(InstanceData *inst); struct PipeAttribute { @@ -181,22 +183,30 @@ void registerPluginPDSPipes(void); struct Ps2Raster { enum Flags { - HASGIFPACKETS = 0x1, - SWIZZLED8 = 0x2, - SWIZZLED4 = 0x4, + NEWSTYLE = 0x1, // has GIF tags and transfer DMA chain + SWIZZLED8 = 0x2, + SWIZZLED4 = 0x4, + }; + struct PixelPtr { + // RW has pixels as second element but we don't want this struct + // to be longer than 16 bytes + uint8 *pixels; + // palette can be allocated in last level, in that case numTransfers is + // one less than numTotalTransfers. + int32 numTransfers; + int32 numTotalTransfers; }; - uint32 tex0[2]; - uint32 paletteOffset; // from beginning of GS data; - // in words/64 + uint64 tex0; + uint32 paletteBase; // block address from beginning of GS data (words/64) uint16 kl; uint8 tex1low; // MXL and LCM of TEX1 uint8 unk2; - uint32 miptbp1[2]; - uint32 miptbp2[2]; - uint32 texelSize; - uint32 paletteSize; - uint32 gsSize; + uint64 miptbp1; + uint64 miptbp2; + uint32 pixelSize; // in bytes + uint32 paletteSize; // in bytes + uint32 totalSize; // total size of texture on GS in words int8 flags; uint8 *data; //tmp diff --git a/src/rwbase.h b/src/rwbase.h index 539fb29..1889139 100644 --- a/src/rwbase.h +++ b/src/rwbase.h @@ -231,6 +231,7 @@ struct Matrix Matrix *rotate(const Quat &q, CombineOp op); Matrix *translate(V3d *translation, CombineOp op); Matrix *scale(V3d *scl, CombineOp op); + Matrix *transform(Matrix *mat, CombineOp op); void lookAt(const V3d &dir, const V3d &up); // helper functions. consider private diff --git a/src/rwengine.h b/src/rwengine.h old mode 100644 new mode 100755 index aa88f9a..dd8352d --- a/src/rwengine.h +++ b/src/rwengine.h @@ -22,9 +22,9 @@ enum RenderState enum AlphaTestFunc { - ALPHANEVER = 0, - ALPHALESS, - ALPHAGREATERTHAN + ALPHAALWAYS = 0, + ALPHAGREATEREQUAL, + ALPHALESS }; enum BlendFunction @@ -43,37 +43,35 @@ enum BlendFunction // TODO: add more perhaps }; -// This is for platform independent things and the render device (of which -// there can only ever be one). -// TODO: move more stuff into this -struct Engine +enum DeviceReq { - void *currentCamera; - void *currentWorld; - Texture *imtexture; + // Device/Context creation + DEVICESTART, + // Device initialization before Engine/Driver plugins are opened + DEVICEINIT, + // Device/Context shutdown + DEVICESTOP, +}; - TexDictionary *currentTexDictionary; - bool32 loadTextures; // load textures from files - bool32 makeDummies; // create dummy textures to store just names +typedef int DeviceSystem(DeviceReq req, void *arg0); - - // Device +// This is for the render device, we only have one +struct Device +{ float32 zNear, zFar; void (*beginUpdate)(Camera*); void (*endUpdate)(Camera*); void (*clearCamera)(Camera*, RGBA *col, uint32 mode); + void (*showRaster)(Raster *raster); void (*setRenderState)(int32 state, uint32 value); uint32 (*getRenderState)(int32 state); void (*im2DRenderIndexedPrimitive)(PrimitiveType, void*, int32, void*, int32); - - static void init(void); + DeviceSystem *system; }; -extern Engine *engine; - -// This is for platform driver implementations which have to be available -// regardless of the render device. +// This is for platform-dependent but portable things +// so the engine has one for every platform struct Driver { ObjPipeline *defaultPipeline; @@ -87,7 +85,6 @@ struct Driver Image *(*rasterToImage)(Raster*); static PluginList s_plglist[NUM_PLATFORMS]; - static void open(void); static int32 registerPlugin(int32 platform, int32 size, uint32 id, Constructor ctor, Destructor dtor){ return s_plglist[platform].registerPlugin(size, id, @@ -95,19 +92,55 @@ struct Driver } }; -extern Driver *driver[NUM_PLATFORMS]; -#define DRIVER driver[rw::platform] +struct EngineStartParams; + +// This is for platform independent things +// TODO: move more stuff into this +// TODO: make this have plugins and allocate in Engine::open +struct Engine +{ + enum State { + Dead = 0, + Initialized, + Opened, + Started + }; + void *currentCamera; + void *currentWorld; + Texture *imtexture; + + TexDictionary *currentTexDictionary; + // load textures from files + bool32 loadTextures; + // create dummy textures to store just names + bool32 makeDummies; + // Dynamically allocated because of plugins + Driver *driver[NUM_PLATFORMS]; + Device device; + + static State state; + + static bool32 init(void); + static bool32 open(void); + static bool32 start(EngineStartParams*); + static void term(void); + static void close(void); + static void stop(void); +}; + +extern Engine *engine; inline void SetRenderState(int32 state, uint32 value){ - engine->setRenderState(state, value); } + engine->device.setRenderState(state, value); } inline uint32 GetRenderState(int32 state){ - return engine->getRenderState(state); } + return engine->device.getRenderState(state); } namespace null { void beginUpdate(Camera*); void endUpdate(Camera*); void clearCamera(Camera*, RGBA *col, uint32 mode); + void showRaster(Raster*); void setRenderState(int32 state, uint32 value); uint32 getRenderState(int32 state); @@ -121,6 +154,10 @@ namespace null { void im2DRenderIndexedPrimitive(PrimitiveType, void*, int32, void*, int32); + + int deviceSystem(DeviceReq req, void*); + + extern Device renderdevice; } } diff --git a/src/rwerror.h b/src/rwerror.h index e382e89..937cc0e 100644 --- a/src/rwerror.h +++ b/src/rwerror.h @@ -20,6 +20,6 @@ char *dbgsprint(int32 code, ...); fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); \ fprintf(stderr, "%s\n", rw::dbgsprint ecode); \ rw::setError(&_e); \ -}while(0); +}while(0) } diff --git a/src/rwobjects.h b/src/rwobjects.h old mode 100644 new mode 100755 index 19f2dd1..afd1846 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -82,8 +82,9 @@ struct Object } }; -struct Frame : PluginBase +struct Frame { + PLUGINBASE typedef Frame *(*Callback)(Frame *f, void *data); enum { ID = 0 }; enum { // private flags @@ -125,7 +126,8 @@ struct Frame : PluginBase Matrix *getLTM(void); void rotate(V3d *axis, float32 angle, CombineOp op); void translate(V3d *trans, CombineOp op); - void scale(V3d *trans, CombineOp op); + void scale(V3d *scale, CombineOp op); + void transform(Matrix *mat, CombineOp op); void updateObjects(void); @@ -214,17 +216,26 @@ struct RasterLevels } levels[1]; // 0 is illegal :/ }; -struct Raster : PluginBase +struct Raster { + PLUGINBASE int32 platform; - int32 type; // hardly used + // TODO: use bytes + int32 type; int32 flags; int32 format; int32 width, height, depth; int32 stride; - uint8 *texels; + uint8 *pixels; uint8 *palette; + uint8 *originalPixels; + // TODO: use them (for locking mainly) + int32 originalWidth; + int32 originalHeight; + int32 originalStride; + // TODO: + // parent raster and offset static Raster *create(int32 width, int32 height, int32 depth, int32 format, int32 platform = 0); @@ -267,8 +278,9 @@ struct Raster : PluginBase struct TexDictionary; -struct Texture : PluginBase +struct Texture { + PLUGINBASE Raster *raster; TexDictionary *dict; LLLink inDict; @@ -316,8 +328,9 @@ struct SurfaceProperties float32 diffuse; }; -struct Material : PluginBase +struct Material { + PLUGINBASE Texture *texture; RGBA color; SurfaceProperties surfaceProps; @@ -390,8 +403,9 @@ struct MaterialList uint32 streamGetSize(void); }; -struct Geometry : PluginBase +struct Geometry { + PLUGINBASE enum { ID = 8 }; Object object; uint32 flags; @@ -452,8 +466,9 @@ void registerNativeDataPlugin(void); struct Clump; struct World; -struct Atomic : PluginBase +struct Atomic { + PLUGINBASE typedef void (*RenderCB)(Atomic *atomic); enum { ID = 1 }; enum { @@ -508,8 +523,9 @@ struct Atomic : PluginBase void registerAtomicRightsPlugin(void); -struct Light : PluginBase +struct Light { + PLUGINBASE enum { ID = 3 }; ObjectWithFrame object; float32 radius; @@ -567,8 +583,9 @@ struct FrustumPlane uint8 closestZ; }; -struct Camera : PluginBase +struct Camera { + PLUGINBASE enum { ID = 4 }; enum { PERSPECTIVE = 1, PARALLEL }; enum { CLEARIMAGE = 0x1, CLEARZ = 0x2}; @@ -612,8 +629,12 @@ struct Camera : PluginBase void beginUpdate(void) { this->beginUpdateCB(this); } void endUpdate(void) { this->endUpdateCB(this); } void clear(RGBA *col, uint32 mode); + void showRaster(void); void setNearPlane(float32); void setFarPlane(float32); + void setViewWindow(const V2d *window); + void setViewOffset(const V2d *offset); + void setProjection(int32 proj); int32 frustumTestSphere(Sphere *s); static Camera *streamRead(Stream *stream); bool streamWrite(Stream *stream); @@ -623,8 +644,9 @@ struct Camera : PluginBase void setFOV(float32 fov, float32 ratio); }; -struct Clump : PluginBase +struct Clump { + PLUGINBASE enum { ID = 2 }; Object object; LinkList atomics; @@ -662,8 +684,9 @@ struct Clump : PluginBase }; // A bit of a stub right now -struct World : PluginBase +struct World { + PLUGINBASE enum { ID = 7 }; Object object; LinkList lights; // these have positions (type >= 0x80) @@ -674,8 +697,9 @@ struct World : PluginBase void addCamera(Camera *cam); }; -struct TexDictionary : PluginBase +struct TexDictionary { + PLUGINBASE enum { ID = 6 }; Object object; LinkList textures; diff --git a/src/rwplg.h b/src/rwplg.h index 9dc082b..38a1bee 100644 --- a/src/rwplg.h +++ b/src/rwplg.h @@ -49,27 +49,22 @@ struct PluginList int32 getPluginOffset(uint32 id); }; -template -struct PluginBase -{ - static PluginList s_plglist; +#define PLUGINBASE \ + static PluginList s_plglist; \ + static int32 registerPlugin(int32 size, uint32 id, Constructor ctor, \ + Destructor dtor, CopyConstructor copy){ \ + return s_plglist.registerPlugin(size, id, ctor, dtor, copy); \ + } \ + static int32 registerPluginStream(uint32 id, StreamRead read, \ + StreamWrite write, StreamGetSize getSize){ \ + return s_plglist.registerStream(id, read, write, getSize); \ + } \ + static int32 setStreamRightsCallback(uint32 id, RightsCallback cb){ \ + return s_plglist.setStreamRightsCallback(id, cb); \ + } \ + static int32 getPluginOffset(uint32 id){ \ + return s_plglist.getPluginOffset(id); \ + } - static int32 registerPlugin(int32 size, uint32 id, Constructor ctor, - Destructor dtor, CopyConstructor copy){ - return s_plglist.registerPlugin(size, id, ctor, dtor, copy); - } - static int32 registerPluginStream(uint32 id, StreamRead read, - StreamWrite write, StreamGetSize getSize){ - return s_plglist.registerStream(id, read, write, getSize); - } - static int32 setStreamRightsCallback(uint32 id, RightsCallback cb){ - return s_plglist.setStreamRightsCallback(id, cb); - } - static int32 getPluginOffset(uint32 id){ - return s_plglist.getPluginOffset(id); - } -}; -template -PluginList PluginBase::s_plglist = { sizeof(T), sizeof(T), nil, nil }; } diff --git a/src/rwplugins.h b/src/rwplugins.h old mode 100644 new mode 100755 index 111c19d..d0edf9f --- a/src/rwplugins.h +++ b/src/rwplugins.h @@ -130,7 +130,7 @@ struct MatFX static void setEffects(Material *m, uint32 flags); static uint32 getEffects(Material *m); static MatFX *get(Material *m); - uint32 getEffectIndex(uint32 type); + int32 getEffectIndex(uint32 type); void setBumpTexture(Texture *t); void setBumpCoefficient(float32 coef); void setEnvTexture(Texture *t); diff --git a/src/world.cpp b/src/world.cpp old mode 100644 new mode 100755 index f63c618..d17def9 --- a/src/world.cpp +++ b/src/world.cpp @@ -13,6 +13,8 @@ namespace rw { +PluginList World::s_plglist = { sizeof(World), sizeof(World), nil, nil }; + World* World::create(void) { @@ -33,14 +35,19 @@ World::addLight(Light *light) light->world = this; if(light->getType() < Light::POINT){ this->directionalLights.append(&light->inWorld); - }else + }else{ this->lights.append(&light->inWorld); + if(light->getFrame()) + light->getFrame()->updateObjects(); + } } void World::addCamera(Camera *cam) { cam->world = this; + if(cam->getFrame()) + cam->getFrame()->updateObjects(); } } diff --git a/tools/clumpview/camera.cpp b/tools/clumpview/camera.cpp new file mode 100644 index 0000000..27185aa --- /dev/null +++ b/tools/clumpview/camera.cpp @@ -0,0 +1,134 @@ +#include +#include + +#include + +#define PI 3.14159265359f +#include "camera.h" + +using rw::Quat; +using rw::V3d; + +void +Camera::update(void) +{ + if(m_rwcam){ + m_rwcam->nearPlane = m_near; + m_rwcam->farPlane = m_far; + m_rwcam->setFOV(m_fov, m_aspectRatio); + + rw::Frame *f = m_rwcam->getFrame(); + if(f){ + V3d forward = normalize(sub(m_target, m_position)); + V3d left = normalize(cross(m_up, forward)); + V3d nup = cross(forward, left); + f->matrix.right = left; // lol + f->matrix.up = nup; + f->matrix.at = forward; + f->matrix.pos = m_position; + f->matrix.optimize(); + f->updateObjects(); + } + } +} + +void +Camera::setTarget(V3d target) +{ + m_position = sub(m_position, sub(m_target, target)); + m_target = target; +} + +float +Camera::getHeading(void) +{ + V3d dir = sub(m_target, m_position); + float a = atan2(dir.y, dir.x)-PI/2.0f; + return m_localup.z < 0.0f ? a-PI : a; +} + +void +Camera::turn(float yaw, float pitch) +{ + V3d dir = sub(m_target, m_position); + Quat r = Quat::rotation(yaw, rw::makeV3d(0.0f, 0.0f, 1.0f)); + dir = rotate(dir, r); + m_localup = rotate(m_localup, r); + + V3d right = normalize(cross(dir, m_localup)); + r = Quat::rotation(pitch, right); + dir = rotate(dir, r); + m_localup = normalize(cross(right, dir)); + if(m_localup.z >= 0.0) m_up.z = 1.0; + else m_up.z = -1.0f; + + m_target = add(m_position, dir); +} + +void +Camera::orbit(float yaw, float pitch) +{ + V3d dir = sub(m_target, m_position); + Quat r = Quat::rotation(yaw, rw::makeV3d(0.0f, 0.0f, 1.0f)); + dir = rotate(dir, r); + m_localup = rotate(m_localup, r); + + V3d right = normalize(cross(dir, m_localup)); + r = Quat::rotation(-pitch, right); + dir = rotate(dir, r); + m_localup = normalize(cross(right, dir)); + if(m_localup.z >= 0.0) m_up.z = 1.0; + else m_up.z = -1.0f; + + m_position = sub(m_target, dir); +} + +void +Camera::dolly(float dist) +{ + V3d dir = setlength(sub(m_target, m_position), dist); + m_position = add(m_position, dir); + m_target = add(m_target, dir); +} + +void +Camera::zoom(float dist) +{ + V3d dir = sub(m_target, m_position); + float curdist = length(dir); + if(dist >= curdist) + dist = curdist-0.01f; + dir = setlength(dir, dist); + m_position = add(m_position, dir); +} + +void +Camera::pan(float x, float y) +{ + V3d dir = normalize(sub(m_target, m_position)); + V3d right = normalize(cross(dir, m_up)); + V3d localup = normalize(cross(right, dir)); + dir = add(scale(right, x), scale(localup, y)); + m_position = add(m_position, dir); + m_target = add(m_target, dir); +} + +float +Camera::distanceTo(V3d v) +{ + return length(sub(m_position, v)); +} + +Camera::Camera() +{ + m_position.set(0.0f, 6.0f, 0.0f); + m_target.set(0.0f, 0.0f, 0.0f); + m_up.set(0.0f, 0.0f, 1.0f); + m_localup = m_up; + m_fov = 70.0f; + m_aspectRatio = 1.0f; + m_near = 0.1f; + m_far = 100.0f; + m_rwcam = NULL; +} + diff --git a/tools/clumpview/camera.h b/tools/clumpview/camera.h new file mode 100644 index 0000000..8a0315d --- /dev/null +++ b/tools/clumpview/camera.h @@ -0,0 +1,26 @@ +class Camera +{ +public: + rw::Camera *m_rwcam; + rw::V3d m_position; + rw::V3d m_target; + rw::V3d m_up; + rw::V3d m_localup; + + float m_fov, m_aspectRatio; + float m_near, m_far; + + + void setTarget(rw::V3d target); + float getHeading(void); + + void turn(float yaw, float pitch); + void orbit(float yaw, float pitch); + void dolly(float dist); + void zoom(float dist); + void pan(float x, float y); + + void update(void); + float distanceTo(rw::V3d v); + Camera(void); +}; diff --git a/tools/clumpview/main.cpp b/tools/clumpview/main.cpp new file mode 100644 index 0000000..124534d --- /dev/null +++ b/tools/clumpview/main.cpp @@ -0,0 +1,181 @@ +#include +#include +#include "camera.h" +#include + +rw::V3d zero = { 0.0f, 0.0f, 0.0f }; +Camera *camera; +rw::Clump *clump; +rw::World *world; +rw::EngineStartParams engineStartParams; + +void +Init(void) +{ + sk::globals.windowtitle = "Clump viewer"; + sk::globals.width = 640; + sk::globals.height = 480; + sk::globals.quit = 0; +} + +bool +attachPlugins(void) +{ + rw::ps2::registerPDSPlugin(40); + rw::ps2::registerPluginPDSPipes(); + + rw::registerMeshPlugin(); + rw::registerNativeDataPlugin(); + rw::registerAtomicRightsPlugin(); + rw::registerMaterialRightsPlugin(); + rw::xbox::registerVertexFormatPlugin(); + rw::registerSkinPlugin(); + rw::registerHAnimPlugin(); + rw::registerMatFXPlugin(); + rw::registerUVAnimPlugin(); + rw::ps2::registerADCPlugin(); + return true; +} + +bool +InitRW(void) +{ +// rw::platform = rw::PLATFORM_D3D8; + if(!sk::InitRW()) + return false; + + char *filename = "teapot.dff"; + rw::StreamFile in; + if(in.open(filename, "rb") == NULL){ + printf("couldn't open file\n"); + return false; + } + rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL); + clump = rw::Clump::streamRead(&in); + assert(clump); + in.close(); + + clump->getFrame()->translate(&zero, rw::COMBINEREPLACE); + + FORLIST(lnk, clump->atomics){ + rw::Atomic *a = rw::Atomic::fromClump(lnk); + if(a->pipeline && a->pipeline->platform != rw::platform) + a->pipeline = NULL; + } + + + world = rw::World::create(); + + rw::Light *ambient = rw::Light::create(rw::Light::AMBIENT); + ambient->setColor(0.2f, 0.2f, 0.2f); + world->addLight(ambient); + + rw::V3d xaxis = { 1.0f, 0.0f, 0.0f }; + rw::Light *direct = rw::Light::create(rw::Light::DIRECTIONAL); + direct->setColor(0.8f, 0.8f, 0.8f); + direct->setFrame(rw::Frame::create()); + direct->getFrame()->rotate(&xaxis, 180.0f, rw::COMBINEREPLACE); + world->addLight(direct); + + camera = new Camera; + camera->m_rwcam = rw::Camera::create(); + camera->m_rwcam->setFrame(rw::Frame::create()); + camera->m_aspectRatio = 640.0f/480.0f; + camera->m_near = 0.1f; + camera->m_far = 450.0f; + camera->m_target.set(0.0f, 0.0f, 0.0f); + camera->m_position.set(0.0f, -10.0f, 0.0f); +// camera->setPosition(Vec3(0.0f, 5.0f, 0.0f)); +// camera->setPosition(Vec3(0.0f, -70.0f, 0.0f)); +// camera->setPosition(Vec3(0.0f, -1.0f, 3.0f)); + camera->update(); + + world->addCamera(camera->m_rwcam); + + return true; +} + +void +Draw(float timeDelta) +{ + static rw::RGBA clearcol = { 0x80, 0x80, 0x80, 0xFF }; + camera->m_rwcam->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ); + camera->update(); + camera->m_rwcam->beginUpdate(); + + clump->render(); + + camera->m_rwcam->endUpdate(); + camera->m_rwcam->showRaster(); +} + + +void +KeyUp(int key) +{ +} + +void +KeyDown(int key) +{ + switch(key){ + case 'W': + camera->orbit(0.0f, 0.1f); + break; + case 'S': + camera->orbit(0.0f, -0.1f); + break; + case 'A': + camera->orbit(-0.1f, 0.0f); + break; + case 'D': + camera->orbit(0.1f, 0.0f); + break; + case sk::KEY_UP: + camera->turn(0.0f, 0.1f); + break; + case sk::KEY_DOWN: + camera->turn(0.0f, -0.1f); + break; + case sk::KEY_LEFT: + camera->turn(0.1f, 0.0f); + break; + case sk::KEY_RIGHT: + camera->turn(-0.1f, 0.0f); + break; + case 'R': + camera->zoom(0.1f); + break; + case 'F': + camera->zoom(-0.1f); + break; + case sk::KEY_ESC: + sk::globals.quit = 1; + break; + } +} + +sk::EventStatus +AppEventHandler(sk::Event e, void *param) +{ + using namespace sk; + switch(e){ + case INITIALIZE: + Init(); + return EVENTPROCESSED; + case RWINITIALIZE: + return ::InitRW() ? EVENTPROCESSED : EVENTERROR; + case PLUGINATTACH: + return attachPlugins() ? EVENTPROCESSED : EVENTERROR; + case KEYDOWN: + KeyDown(*(int*)param); + return EVENTPROCESSED; + case KEYUP: + KeyUp(*(int*)param); + return EVENTPROCESSED; + case IDLE: + Draw(*(float*)param); + return EVENTPROCESSED; + } + return sk::EVENTNOTPROCESSED; +} diff --git a/tools/clumpview/teapot.dff b/tools/clumpview/teapot.dff new file mode 100644 index 0000000..7a65176 Binary files /dev/null and b/tools/clumpview/teapot.dff differ diff --git a/tools/ps2test/gs.h b/tools/ps2test/gs.h new file mode 100755 index 0000000..361ad8c --- /dev/null +++ b/tools/ps2test/gs.h @@ -0,0 +1,437 @@ +#define GS_NONINTERLACED 0 +#define GS_INTERLACED 1 + +#define GS_NTSC 2 +#define GS_PAL 3 +#define GS_VESA1A 0x1a +#define GS_VESA1B 0x1b +#define GS_VESA1C 0x1c +#define GS_VESA1D 0x1d +#define GS_VESA2A 0x2a +#define GS_VESA2B 0x2b +#define GS_VESA2C 0x2c +#define GS_VESA2D 0x2d +#define GS_VESA2E 0x2e +#define GS_VESA3B 0x3b +#define GS_VESA3C 0x3c +#define GS_VESA3D 0x3d +#define GS_VESA3E 0x3e +#define GS_VESA4A 0x4a +#define GS_VESA4B 0x4b +#define GS_DTV480P 0x50 + +#define GS_FIELD 0 +#define GS_FRAME 1 + +#define GS_PSMCT32 0 +#define GS_PSMCT24 1 +#define GS_PSMCT16 2 +#define GS_PSMCT16S 10 +#define GS_PS_GPU24 18 + +#define GS_PSMZ32 0 +#define GS_PSMZ24 1 +#define GS_PSMZ16 2 +#define GS_PSMZ16S 10 + +#define GS_ZTST_NEVER 0 +#define GS_ZTST_ALWAYS 1 +#define GS_ZTST_GREATER 2 +#define GS_ZTST_GEQUAL 3 + +#define GS_PRIM_POINT 0 +#define GS_PRIM_LINE 1 +#define GS_PRIM_LINE_STRIP 2 +#define GS_PRIM_TRI 3 +#define GS_PRIM_TRI_STRIP 4 +#define GS_PRIM_TRI_FAN 5 +#define GS_PRIM_SPRITE 6 +#define GS_PRIM_NO_SPEC 7 +#define GS_IIP_FLAT 0 +#define GS_IIP_GOURAUD 1 + +/* GS general purpose registers */ + +#define GS_PRIM 0x00 +#define GS_RGBAQ 0x01 +#define GS_ST 0x02 +#define GS_UV 0x03 +#define GS_XYZF2 0x04 +#define GS_XYZ2 0x05 +#define GS_TEX0_1 0x06 +#define GS_TEX0_2 0x07 +#define GS_CLAMP_1 0x08 +#define GS_CLAMP_2 0x09 +#define GS_FOG 0x0a +#define GS_XYZF3 0x0c +#define GS_XYZ3 0x0d +#define GS_TEX1_1 0x14 +#define GS_TEX1_2 0x15 +#define GS_TEX2_1 0x16 +#define GS_TEX2_2 0x17 +#define GS_XYOFFSET_1 0x18 +#define GS_XYOFFSET_2 0x19 +#define GS_PRMODECONT 0x1a +#define GS_PRMODE 0x1b +#define GS_TEXCLUT 0x1c +#define GS_SCANMSK 0x22 +#define GS_MIPTBP1_1 0x34 +#define GS_MIPTBP1_2 0x35 +#define GS_MIPTBP2_1 0x36 +#define GS_MIPTBP2_2 0x37 +#define GS_TEXA 0x3b +#define GS_FOGCOL 0x3d +#define GS_TEXFLUSH 0x3f +#define GS_SCISSOR_1 0x40 +#define GS_SCISSOR_2 0x41 +#define GS_ALPHA_1 0x42 +#define GS_ALPHA_2 0x43 +#define GS_DIMX 0x44 +#define GS_DTHE 0x45 +#define GS_COLCLAMP 0x46 +#define GS_TEST_1 0x47 +#define GS_TEST_2 0x48 +#define GS_PABE 0x49 +#define GS_FBA_1 0x4a +#define GS_FBA_2 0x4b +#define GS_FRAME_1 0x4c +#define GS_FRAME_2 0x4d +#define GS_ZBUF_1 0x4e +#define GS_ZBUF_2 0x4f +#define GS_BITBLTBUF 0x50 +#define GS_TRXPOS 0x51 +#define GS_TRXREG 0x52 +#define GS_TRXDIR 0x53 +#define GS_HWREG 0x54 +#define GS_SIGNAL 0x60 +#define GS_FINISH 0x61 +#define GS_LABEL 0x62 + +typedef union +{ + struct { + uint64 EN1 : 1; + uint64 EN2 : 1; + uint64 CRTMD : 3; + uint64 MMOD : 1; + uint64 AMOD : 1; + uint64 SLBG : 1; + uint64 ALP : 8; + } f; + uint64 d; +} GsPmode; + +#define GS_MAKE_PMODE(EN1,EN2,MMOD,AMOD,SLBG,ALP) \ + (BIT64(EN1,0) | BIT64(EN2,1) | BIT64(1,2) | \ + BIT64(MMOD,5) | BIT64(AMOD,6) | BIT64(SLBG,7) | BIT64(ALP,8)) + +typedef union +{ + struct { + uint64 INT : 1; + uint64 FFMD : 1; + uint64 DPMS : 2; + } f; + uint64 d; +} GsSmode2; + +#define GS_MAKE_SMODE2(INT,FFMD,DPMS) \ + (BIT64(INT,0) | BIT64(FFMD,1) | BIT64(DPMS,2)) + +typedef union +{ + struct { + uint64 FBP : 9; + uint64 FBW : 6; + uint64 PSM : 5; + uint64 : 12; + uint64 DBX : 11; + uint64 DBY : 11; + } f; + uint64 d; +} GsDispfb; + +#define GS_MAKE_DISPFB(FBP,FBW,PSM,DBX,DBY) \ + (BIT64(FBP,0) | BIT64(FBW,9) | BIT64(PSM,15) | \ + BIT64(DBX,32) | BIT64(DBY,43)) + +typedef union +{ + struct { + uint64 DX : 12; + uint64 DY : 11; + uint64 MAGH : 4; + uint64 MAGV : 2; + uint64 : 3; + uint64 DW : 12; + uint64 DH : 11; + } f; + uint64 d; +} GsDisplay; + +#define GS_MAKE_DISPLAY(DX,DY,MAGH,MAGV,DW,DH) \ + (BIT64(DX,0) | BIT64(DY,12) | BIT64(MAGH,23) | \ + BIT64(MAGV,27) | BIT64(DW,32) | BIT64(DH,44)) + +typedef union +{ + struct { + uint64 EXBP : 14; + uint64 EXBW : 6; + uint64 FBIN : 2; + uint64 WFFMD : 1; + uint64 EMODA : 2; + uint64 EMODC : 2; + uint64 : 5; + uint64 WDX : 11; + uint64 WDY : 11; + } f; + uint64 d; +} GsExtbuf; + +#define GS_MAKE_EXTBUF(EXBP,EXBW,FBIN,WFFMD,EMODA,EMODC,WDX,WDY) \ + (BIT64(EXBP,0) | BIT64(EXBW,14) | BIT64(FBIN,20) | \ + BIT64(WFFMD,22) | BIT64(EMODA,23) | BIT64(EMODC,25) | \ + BIT64(WDX,32) | BIT64(WDY,43)) + +typedef union +{ + struct { + uint64 SX : 12; + uint64 SY : 11; + uint64 SMPH : 4; + uint64 SMPV : 2; + uint64 : 3; + uint64 WW : 12; + uint64 WH : 11; + } f; + uint64 d; +} GsExtdata; + +#define GS_MAKE_EXTDATA(SX,SY,SMPH,SMPV,WW,WH) \ + (BIT64(SX,0) | BIT64(SY,12) | BIT64(SMPH,23) | \ + BIT64(SMPV,27) | BIT64(WW,32) | BIT64(WH,44)) + +typedef union +{ + struct { + uint64 WRITE : 1; + } f; + uint64 d; +} GsExtwrite; + +typedef union +{ + struct { + uint64 R : 8; + uint64 G : 8; + uint64 B : 8; + } f; + uint64 d; +} GsBgcolor; + +#define GS_MAKE_BGCOLOR(R,G,B) \ + (BIT64(R,0) | BIT64(G,8) | BIT64(B,16)) + +typedef union +{ + struct { + uint64 SIGNAL : 1; + uint64 FINISH : 1; + uint64 HSINT : 1; + uint64 VSINT : 1; + uint64 EDWINT : 1; + uint64 : 3; + uint64 FLUSH : 1; + uint64 RESET : 1; + uint64 : 2; + uint64 NFIELD : 1; + uint64 FIELD : 1; + uint64 FIFO : 2; + uint64 REV : 8; + uint64 ID : 8; + } f; + uint64 d; +} GsCsr; + +#define GS_CSR_SIGNAL_O 0 +#define GS_CSR_FINISH_O 1 +#define GS_CSR_HSINT_O 2 +#define GS_CSR_VSINT_O 3 +#define GS_CSR_EDWINT_O 4 +#define GS_CSR_FLUSH_O 8 +#define GS_CSR_RESET_O 9 +#define GS_CSR_NFIELD_O 12 +#define GS_CSR_FIELD_O 13 +#define GS_CSR_FIFO_O 14 +#define GS_CSR_REV_O 16 +#define GS_CSR_ID_O 24 + +typedef union +{ + struct { + uint64 : 8; + uint64 SIGMSK : 1; + uint64 FINISHMSK : 1; + uint64 HSMSKMSK : 1; + uint64 VSMSKMSK : 1; + uint64 EDWMSKMSK : 1; + } f; + uint64 d; +} GsImr; + +typedef union +{ + struct { + uint64 DIR : 1; + } f; + uint64 d; +} GsBusdir; + +typedef union +{ + struct { + uint64 SIGID : 32; + uint64 LBLID : 32; + } f; + uint64 d; +} GsSiglblid; + + +typedef union +{ + struct { + uint64 FBP : 9; + uint64 : 7; + uint64 FBW : 6; + uint64 : 2; + uint64 PSM : 6; + uint64 : 2; + uint64 FBMSK : 32; + } f; + uint64 d; +} GsFrame; + +#define GS_MAKE_FRAME(FBP,FBW,PSM,FBMASK) \ + (BIT64(FBP,0) | BIT64(FBW,16) | BIT64(PSM,24) | BIT64(FBMASK,32)) + +typedef union +{ + struct { + uint64 ZBP : 9; + uint64 : 15; + uint64 PSM : 4; + uint64 : 4; + uint64 ZMSDK : 1; + } f; + uint64 d; +} GsZbuf; + +#define GS_MAKE_ZBUF(ZBP,PSM,ZMSK) \ + (BIT64(ZBP,0) | BIT64(PSM,24) | BIT64(ZMSK,32)) + +typedef union +{ + struct { + uint64 OFX : 16; + uint64 : 16; + uint64 OFY : 16; + } f; + uint64 d; +} GsXyOffset; + +#define GS_MAKE_XYOFFSET(OFX,OFY) \ + (BIT64(OFX,0) | BIT64(OFY,32)) + +typedef union +{ + struct { + uint64 SCAX0 : 11; + uint64 : 5; + uint64 SCAX1 : 11; + uint64 : 5; + uint64 SCAY0 : 11; + uint64 : 5; + uint64 SCAY1 : 11; + } f; + uint64 d; +} GsScissor; + +#define GS_MAKE_SCISSOR(SCAX0,SCAX1,SCAY0,SCAY1) \ + (BIT64(SCAX0,0) | BIT64(SCAX1,16) | BIT64(SCAY0,32) | BIT64(SCAY1,48)) + +#define GS_MAKE_TEST(ATE,ATST,AREF,AFAIL,DATE,DATM,ZTE,ZTST) \ + (BIT64(ATE,0) | BIT64(ATST,1) | BIT64(AREF,4) | BIT64(AFAIL,12) | \ + BIT64(DATE,14) | BIT64(DATM,15) | BIT64(ZTE,16) | BIT64(ZTST,17)) + +#define GS_MAKE_PRIM(PRIM,IIP,TME,FGE,ABE,AA1,FST,CTXT,FIX) \ + (BIT64(PRIM,0) | BIT64(IIP,3) | BIT64(TME,4) | BIT64(FGE,5) | \ + BIT64(ABE,6) | BIT64(AA1,7) | BIT64(FST,8) | BIT64(CTXT,9) | BIT64(FIX,10)) + +#define GS_MAKE_RGBAQ(R,G,B,A,Q) \ + (BIT64(R,0) | BIT64(G,8) | BIT64(B,16) | BIT64(A,24) | BIT64(Q,32)) + +#define GS_MAKE_XYZ(X,Y,Z) \ + (BIT64(X,0) | BIT64(Y,16) | BIT64(Z,32)) + +#define GIF_PACKED 0 +#define GIF_REGLIST 1 +#define GIF_IMAGE 2 + +#define GIF_MAKE_TAG(NLOOP,EOP,PRE,PRIM,FLG,NREG) \ + (BIT64(NLOOP,0) | BIT64(EOP,15) | BIT64(PRE,46) | \ + BIT64(PRIM,47) | BIT64(FLG,58) | BIT64(NREG,60)) + +/* This is global and not tied to a user context because + * it is set up by kernel functions and not really changed + * afterwards. */ +typedef struct GsCrtState GsCrtState; +struct GsCrtState +{ + short inter, mode, ff; +}; +extern GsCrtState gsCrtState; + +typedef struct GsDispCtx GsDispCtx; +struct GsDispCtx +{ + // two circuits + GsPmode pmode; + GsDispfb dispfb1; + GsDispfb dispfb2; + GsDisplay display1; + GsDisplay display2; + GsBgcolor bgcolor; +}; + +typedef struct GsDrawCtx GsDrawCtx; +struct GsDrawCtx +{ + //two contexts + uint128 gifTag; + GsFrame frame1; + uint64 ad_frame1; + GsFrame frame2; + uint64 ad_frame2; + GsZbuf zbuf1; + uint64 ad_zbuf1; + GsZbuf zbuf2; + uint64 ad_zbuf2; + GsXyOffset xyoffset1; + uint64 ad_xyoffset1; + GsXyOffset xyoffset2; + uint64 ad_xyoffset2; + GsScissor scissor1; + uint64 ad_scissor1; + GsScissor scissor2; + uint64 ad_scissor2; +}; + +typedef struct GsCtx GsCtx; +struct GsCtx +{ + // display context; two buffers + GsDispCtx disp[2]; + // draw context; two buffers + GsDrawCtx draw[2]; +}; diff --git a/tools/ps2test/main.cpp b/tools/ps2test/main.cpp new file mode 100755 index 0000000..330400a --- /dev/null +++ b/tools/ps2test/main.cpp @@ -0,0 +1,744 @@ +#include +#include + +#include +using rw::uint8; +using rw::uint16; +using rw::uint32; +using rw::uint64; +using rw::int8; +using rw::int16; +using rw::int32; +using rw::int64; +using rw::bool32; +using rw::float32; +typedef uint8 uchar; +typedef uint16 ushort; +typedef uint32 uint; + +#define WIDTH 640 +#define HEIGHT 448 + +#include "ps2.h" + +// getting undefined references otherwise :/ +int *__errno() { return &errno; } + +// NONINTERLACED and FRAME have half of the FIELD vertical resolution! +// NONINTERLACED has half the vertical units + +uint128 packetbuf[128]; +uint128 vuXYZScale; +uint128 vuXYZOffset; +extern uint32 geometryCall[]; +extern uint32 skinPipe[]; + +uint128 *curVifPtr; +uint128 lightpacket[128]; +int32 numLightQ; + + + +rw::World *world; +rw::Camera *camera; + + +int frames; + +void +printquad(uint128 p) +{ + uint64 *lp; + lp = (uint64*)&p; + printf("%016lx %016lx\n", lp[1], lp[0]); +} + +void +printquad4(uint128 p) +{ + uint32 *lp; + lp = (uint32*)&p; + printf("%08x %08x %08x %08x\n", lp[0], lp[1], lp[2], lp[3]); +} + +void +dump4(uint128 *p, int n) +{ +printf("data at %p\n", p); + while(n--) + printquad4(*p++); +} + +struct DmaChannel { + uint32 chcr; uint32 pad0[3]; + uint32 madr; uint32 pad1[3]; + uint32 qwc; uint32 pad2[3]; + uint32 tadr; uint32 pad3[3]; + uint32 asr0; uint32 pad4[3]; + uint32 asr1; uint32 pad5[3]; + uint32 pad6[8]; + uint32 sadr; +}; + +static struct DmaChannel *dmaChannels[] = { + (struct DmaChannel *) &D0_CHCR, + (struct DmaChannel *) &D1_CHCR, + (struct DmaChannel *) &D2_CHCR, + (struct DmaChannel *) &D3_CHCR, + (struct DmaChannel *) &D4_CHCR, + (struct DmaChannel *) &D5_CHCR, + (struct DmaChannel *) &D6_CHCR, + (struct DmaChannel *) &D7_CHCR, + (struct DmaChannel *) &D8_CHCR, + (struct DmaChannel *) &D9_CHCR +}; + +void +dmaReset(void) +{ + /* don't clear the SIF channels */ + int doclear[] = { 1, 1, 1, 1, 1, 0, 0, 0, 1, 1 }; + int i; + + D_CTRL = 0; + for(i = 0; i < 10; i++) + if(doclear[i]){ + dmaChannels[i]->chcr = 0; + dmaChannels[i]->madr = 0; + dmaChannels[i]->qwc = 0; + dmaChannels[i]->tadr = 0; + dmaChannels[i]->asr0 = 0; + dmaChannels[i]->asr1 = 0; + dmaChannels[i]->sadr = 0; + } + D_CTRL = 1; +} + +void +waitDMA(volatile uint32 *chcr) +{ + while(*chcr & (1<<8)); +} + +void +qwcpy(uint128 *dst, uint128 *src, int n) +{ + while(n--) *dst++ = *src++; +} + +void +toGIF(void *src, int n) +{ + FlushCache(0); + D2_QWC = n; + D2_MADR = (uint32)src; + D2_CHCR = 1<<8; + waitDMA(&D2_CHCR); +} + +void +toGIFchain(void *src) +{ + FlushCache(0); + D2_QWC = 0; + D2_TADR = (uint32)src & 0x0FFFFFFF; + D2_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8; + waitDMA(&D2_CHCR); +} + +void +toVIF1chain(void *src) +{ + FlushCache(0); + D1_QWC = 0; + D1_TADR = (uint32)src & 0x0FFFFFFF; + D1_CHCR = 1<<0 | 1<<2 | 1<<6 | 1<<8; + waitDMA(&D1_CHCR); +} + + +GsCrtState gsCrtState; + +int psmsizemap[64] = { + 4, // GS_PSMCT32 + 4, // GS_PSMCT24 + 2, // GS_PSMCT16 + 0, 0, 0, 0, 0, 0, 0, + 2, // GS_PSMCT16S + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, // GS_PSMZ32 + 4, // GS_PSMZ24 + 2, // GS_PSMZ16 + 2, // GS_PSMZ16S + 0, 0, 0, 0, 0 +}; + +void +GsResetCrt(uchar inter, uchar mode, uchar ff) +{ + gsCrtState.inter = inter; + gsCrtState.mode = mode; + gsCrtState.ff = ff; + GS_CSR = 1 << GS_CSR_RESET_O; + __asm__("sync.p; nop"); + GsPutIMR(0xff00); + SetGsCrt(gsCrtState.inter, gsCrtState.mode, gsCrtState.ff); +} + +uint gsAllocPtr = 0; + +void +GsInitDispCtx(GsDispCtx *disp, int width, int height, int psm) +{ + int magh, magv; + int dx, dy; + int dw, dh; + + dx = gsCrtState.mode == GS_NTSC ? 636 : 656; + dy = gsCrtState.mode == GS_NTSC ? 25 : 36; + magh = 2560/width - 1; + magv = 0; + dw = 2560-1; + dh = height-1; + + if(gsCrtState.inter == GS_INTERLACED){ + dy *= 2; + if(gsCrtState.ff == GS_FRAME) + dh = (dh+1)*2-1; + } + + disp->pmode.d = GS_MAKE_PMODE(0, 1, 1, 1, 0, 0x00); + disp->bgcolor.d = 0x404040; + disp->dispfb1.d = 0; + disp->dispfb2.d = GS_MAKE_DISPFB(0, width/64, psm, 0, 0); + disp->display1.d = 0; + disp->display2.d = GS_MAKE_DISPLAY(dx, dy, magh, magv, dw, dh); +} + +void +GsPutDispCtx(GsDispCtx *disp) +{ + GS_PMODE = disp->pmode.d; + GS_DISPFB1 = disp->dispfb1.d; + GS_DISPLAY1 = disp->display1.d; + GS_DISPFB2 = disp->dispfb2.d; + GS_DISPLAY2 = disp->display2.d; + GS_BGCOLOR = disp->bgcolor.d; +} + +void +GsInitDrawCtx(GsDrawCtx *draw, int width, int height, int psm, int zpsm) +{ + MAKE128(draw->gifTag, 0xe, + GIF_MAKE_TAG(8, 1, 0, 0, GIF_PACKED, 1)); + draw->frame1.d = GS_MAKE_FRAME(0, width/64, psm, 0); + draw->ad_frame1 = GS_FRAME_1; + draw->frame2.d = draw->frame1.d; + draw->ad_frame2 = GS_FRAME_2; + draw->zbuf1.d = GS_MAKE_ZBUF(0, zpsm, 0); + draw->ad_zbuf1 = GS_ZBUF_1; + draw->zbuf2.d = draw->zbuf1.d; + draw->ad_zbuf2 = GS_ZBUF_2; + draw->xyoffset1.d = GS_MAKE_XYOFFSET(2048<<4, 2048<<4); + draw->ad_xyoffset1 = GS_XYOFFSET_1; + draw->xyoffset2.d = draw->xyoffset1.d; + draw->ad_xyoffset2 = GS_XYOFFSET_2; + draw->scissor1.d = GS_MAKE_SCISSOR(0, width-1, 0, height-1); + draw->ad_scissor1 = GS_SCISSOR_1; + draw->scissor2.d = draw->scissor1.d; + draw->ad_scissor2 = GS_SCISSOR_2; +} + +void +GsPutDrawCtx(GsDrawCtx *draw) +{ + printquad(*(uint128*)&draw->frame1); + toGIF(draw, 9); +} + +void +GsInitCtx(GsCtx *ctx, int width, int height, int psm, int zpsm) +{ + uint fbsz, zbsz; + uint fbp, zbp; + fbsz = (width*height*psmsizemap[psm] + 2047)/2048; + zbsz = (width*height*psmsizemap[0x30|zpsm] + 2047)/2048; + gsAllocPtr = 2*fbsz + zbsz; + fbp = fbsz; + zbp = fbsz*2; + + GsInitDispCtx(&ctx->disp[0], width, height, psm); + GsInitDispCtx(&ctx->disp[1], width, height, psm); + GsInitDrawCtx(&ctx->draw[0], width, height, psm, zpsm); + GsInitDrawCtx(&ctx->draw[1], width, height, psm, zpsm); + ctx->disp[1].dispfb2.f.FBP = fbp/4; + ctx->draw[0].frame1.f.FBP = fbp/4; + ctx->draw[0].frame2.f.FBP = fbp/4; + ctx->draw[0].zbuf1.f.ZBP = zbp/4; + ctx->draw[0].zbuf2.f.ZBP = zbp/4; + ctx->draw[1].zbuf1.f.ZBP = zbp/4; + ctx->draw[1].zbuf2.f.ZBP = zbp/4; +} + +void +initrender(void) +{ + uint128 *p, tmp; + p = packetbuf; + MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1)); + *p++ = tmp; + MAKE128(tmp, GS_PRMODECONT, 1); + *p++ = tmp; + MAKE128(tmp, GS_COLCLAMP, 1); + *p++ = tmp; + toGIF(packetbuf, 3); +} + +void +clearscreen(int r, int g, int b) +{ + int x, y; + uint128 *p, tmp; + p = packetbuf; + + x = (2048 + 640)<<4; + y = (2048 + 448)<<4; + + MAKE128(tmp, 0xe, GIF_MAKE_TAG(5, 1, 0, 0, GIF_PACKED, 1)); + *p++ = tmp; + MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1)); + *p++ = tmp; + MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(r, g, b, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(2048<<4, 2048<<4, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x, y, 0)); + *p++ = tmp; + toGIF(packetbuf, 6); +} + +void +drawtest(void) +{ + int x0, x1, x2, x3; + int y0, y1, y2; + uint128 *p, tmp; + int n; + + x0 = 2048<<4; + x1 = (2048 + 210)<<4; + x2 = (2048 + 430)<<4; + x3 = (2048 + 640)<<4; + y0 = 2048<<4; + y1 = (2048 + 224)<<4; + y2 = (2048 + 448)<<4; + + n = 2 + 3*7; + p = packetbuf; + MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0); + *p++ = tmp; + MAKE128(tmp, 0xe, GIF_MAKE_TAG(n, 1, 0, 0, GIF_PACKED, 1)); + *p++ = tmp; + MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 1)); + *p++ = tmp; + MAKE128(tmp, GS_PRIM, GS_MAKE_PRIM(GS_PRIM_SPRITE,0,0,0,0,0,0,0,0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 0, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 0, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 0, 255, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y1, 0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(0, 255, 255, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x0, y1, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y2, 0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 0, 255, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x1, y1, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y2, 0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 0, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x2, y1, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, y2, 0)); + *p++ = tmp; + MAKE128(tmp, GS_RGBAQ, GS_MAKE_RGBAQ(255, 255, 255, 0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ((2048+20)<<4, y0, 0)); + *p++ = tmp; + MAKE128(tmp, GS_XYZ2, GS_MAKE_XYZ(x3, (2048+20)<<4, 0)); + *p++ = tmp; + toGIFchain(packetbuf); +} + +void +drawtri(void) +{ + uint128 *p, tmp; + uint32 *ip; + int nverts, n; + + nverts = 3; + n = 2*nverts; + p = packetbuf; + MAKEQ(tmp, 0x70000000 | n+1, 0, 0, 0); + *p++ = tmp; + MAKE128(tmp, (0x5<<4) | 0x1, + GIF_MAKE_TAG(nverts, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI, 1, 0, 0, 0, 0, 0, 0, 0), GIF_PACKED, 2)); + *p++ = tmp; + MAKEQ(tmp, 255, 0, 0, 0); + *p++ = tmp; + MAKEQ(tmp, (2048+85)<<4, (2048+70)<<4, 0, 0); + *p++ = tmp; + MAKEQ(tmp, 0, 255, 0, 0); + *p++ = tmp; + MAKEQ(tmp, (2048+260)<<4, (2048+200)<<4, 0, 0); + *p++ = tmp; + MAKEQ(tmp, 0, 0, 255, 0); + *p++ = tmp; + MAKEQ(tmp, (2048+180)<<4, (2048+350)<<4, 0, 0); + *p++ = tmp; + toGIFchain(packetbuf); +} + +void +printMatrix(rw::Matrix *m) +{ + rw::V3d *x = &m->right; + rw::V3d *y = &m->up; + rw::V3d *z = &m->at; + rw::V3d *w = &m->pos; + printf( + "[ [ %8.4f, %8.4f, %8.4f, %8.4f ]\n" + " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n" + " [ %8.4f, %8.4f, %8.4f, %8.4f ]\n" + " [ %8.4f, %8.4f, %8.4f, %8.4f ] ]\n" + " %08x == flags\n", + x->x, y->x, z->x, w->x, + x->y, y->y, z->y, w->y, + x->z, y->z, z->z, w->z, + 0.0f, 0.0f, 0.0f, 1.0f, + m->flags); +} + +// This is not proper data, just for testing +void +setupLight(rw::Atomic *atomic) +{ + using namespace rw; + Matrix *lightmat; + float32 *lp; + + numLightQ = 0; + lp = (float32*)lightpacket; + + // TODO: this is the wrong matrix. we actually want to + // transform the light, not all normals. + lightmat = atomic->getFrame()->getLTM(); + *lp++ = lightmat->right.x; + *lp++ = lightmat->right.y; + *lp++ = lightmat->right.z; + *lp++ = 0.0f; + *lp++ = lightmat->up.x; + *lp++ = lightmat->up.y; + *lp++ = lightmat->up.z; + *lp++ = 0.0f; + *lp++ = lightmat->at.x; + *lp++ = lightmat->at.y; + *lp++ = lightmat->at.z; + *lp++ = 0.0f; + *lp++ = lightmat->pos.x; + *lp++ = lightmat->pos.y; + *lp++ = lightmat->pos.z; + *lp++ = 1.0f; + // TODO: make a proper light block + // ambient + *lp++ = 80.0f; + *lp++ = 80.0f; + *lp++ = 80.0f; + *lp++ = 0.0f; + // directional + *lp++ = 0.5f; + *lp++ = -0.5f; + *lp++ = -0.7071f; + *lp++ = 0.0f; + numLightQ = 6; +} + +void +setupTransform(rw::Atomic *atomic, rw::Matrix *trans) +{ + rw::Matrix::mult(trans, atomic->getFrame()->getLTM(), &camera->viewMatrix); +} + +enum { + DMAcnt = 0x10000000, + DMAref = 0x30000000, + DMAcall = 0x50000000, + DMAret = 0x60000000, + DMAend = 0x70000000, + + V4_32 = 0x6C +}; + +#define UNPACK(type, nq, offset) ((type)<<24 | (nq)<<16 | (offset)) +#define STCYCL(WL,CL) (0x01000000 | (WL)<<8 | (CL)) + +void +drawAtomic(rw::Atomic *atomic) +{ + using namespace rw; + + Matrix trans; + Geometry *geo; + ps2::ObjPipeline *pipe; + ps2::MatPipeline *matpipe; + Material *material; + uint128 tmp, *lp; + uint32 *vec; + RGBAf color; + int i; + + geo = atomic->geometry; + pipe = (ps2::ObjPipeline*)atomic->getPipeline(); + if(pipe->platform != PLATFORM_PS2) + return; + + setupLight(atomic); + setupTransform(atomic, &trans); + + curVifPtr = packetbuf; + // upload lights + MAKEQ(tmp, DMAcnt | numLightQ+8, 0, STCYCL(4,4), UNPACK(V4_32, numLightQ, 0x3d0)); + *curVifPtr++ = tmp; + for(lp = lightpacket; numLightQ--;) + *curVifPtr++ = *lp++; + + // upload transformation matrix + MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 4, 0x3f0)); + *curVifPtr++ = tmp; + vec = (uint32*)&trans.right; + MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); + *curVifPtr++ = tmp; + vec = (uint32*)&trans.up; + MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); + *curVifPtr++ = tmp; + vec = (uint32*)&trans.at; + MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); + *curVifPtr++ = tmp; + vec = (uint32*)&trans.pos; + MAKEQ(tmp, vec[0], vec[1], vec[2], vec[2]); + *curVifPtr++ = tmp; + + // upload camera/screen info + MAKEQ(tmp, 0, 0, STCYCL(4,4), UNPACK(V4_32, 2, 0x3f7)); + *curVifPtr++ = tmp; + *curVifPtr++ = vuXYZScale; + *curVifPtr++ = vuXYZOffset; + + assert(geo->instData != NULL); + rw::ps2::InstanceDataHeader *instData = + (rw::ps2::InstanceDataHeader*)geo->instData; + rw::MeshHeader *meshHeader = geo->meshHeader; + rw::Mesh *mesh; + for(i = 0; i < instData->numMeshes; i++){ + material = instData->instanceMeshes[i].material; + matpipe = pipe->groupPipeline; + if(matpipe == nil) + matpipe = (ps2::MatPipeline*)material->pipeline; + if(matpipe == nil) + matpipe = ps2::defaultMatPipe; + + // call vu code + MAKEQ(tmp, DMAcall, (uint32)skinPipe, 0, 0); + *curVifPtr++ = tmp; + // unpack GIF tag, material color, surface properties + MAKEQ(tmp, DMAcnt | 3, 0, STCYCL(4,4), UNPACK(V4_32, 3, 0x3fa)); + *curVifPtr++ = tmp; + MAKE128(tmp, 0x412, + GIF_MAKE_TAG(0, 1, 1, GS_MAKE_PRIM(GS_PRIM_TRI_STRIP,1,0,0,0,0,0,0,0), GIF_PACKED, 3)); + *curVifPtr++ = tmp; + convColor(&color, &material->color); + color.alpha *= 128.0f/255.0f; + MAKEQ(tmp, *(uint32*)&color.red, *(uint32*)&color.green, + *(uint32*)&color.blue, *(uint32*)&color.alpha); + *curVifPtr++ = tmp; + MAKEQ(tmp, *(uint32*)&material->surfaceProps.ambient, + *(uint32*)&material->surfaceProps.specular, + *(uint32*)&material->surfaceProps.diffuse, + 0.0f); // extra + *curVifPtr++ = tmp; + // call geometry + MAKEQ(tmp, DMAcall, (uint32)instData->instanceMeshes[i].data, 0x03000000, 0x02000000 | matpipe->vifOffset); + *curVifPtr++ = tmp; + } + MAKEQ(tmp, DMAend, 0, 0, 0); + *curVifPtr++ = tmp; + for(lp = packetbuf; lp < curVifPtr; lp++) + printquad4(*lp); + toVIF1chain(packetbuf); +} + +void +beginCamera(void) +{ + uint128 *p, tmp; + float32 *f; + + p = packetbuf; + MAKE128(tmp, 0xe, GIF_MAKE_TAG(2, 1, 0, 0, GIF_PACKED, 1)); + *p++ = tmp; + MAKE128(tmp, GS_XYOFFSET_1, GS_MAKE_XYOFFSET(2048-WIDTH/2 <<4, 2048-HEIGHT/2 <<4)); + *p++ = tmp; + MAKE128(tmp, GS_TEST_1, GS_MAKE_TEST(0, 0, 0, 0, 0, 0, 1, 2)); + *p++ = tmp; + toGIF(packetbuf, 3); + f = (float32*)&vuXYZScale; + f[0] = WIDTH; + f[1] = HEIGHT; + f[2] = camera->zScale; + f[3] = 0.0f; + f = (float32*)&vuXYZOffset; + f[0] = 2048.0f; + f[1] = 2048.0f; + f[2] = camera->zShift; + f[3] = 0.0f; +} + +rw::EngineStartParams engineStartParams; + +void +pluginattach(void) +{ + rw::ps2::registerPDSPlugin(40); + rw::ps2::registerPluginPDSPipes(); + + rw::registerMeshPlugin(); + rw::registerNativeDataPlugin(); + rw::registerAtomicRightsPlugin(); + rw::registerMaterialRightsPlugin(); + rw::xbox::registerVertexFormatPlugin(); + rw::registerSkinPlugin(); + rw::registerHAnimPlugin(); + rw::registerMatFXPlugin(); + rw::registerUVAnimPlugin(); + rw::ps2::registerADCPlugin(); +} + +bool32 +initrw(void) +{ + rw::version = 0x34000; + rw::platform = rw::PLATFORM_PS2; + if(!rw::Engine::init()) + return 0; + pluginattach(); + if(!rw::Engine::open()) + return 0; + if(!rw::Engine::start(&engineStartParams)) + return 0; + rw::engine->loadTextures = 0; + + rw::TexDictionary::setCurrent(rw::TexDictionary::create()); + rw::Image::setSearchPath("."); + + world = rw::World::create(); + camera = rw::Camera::create(); + camera->setFrame(rw::Frame::create()); + rw::V3d t = { 0.0f, 0.0f, -4.0f }; +// rw::V3d t = { 0.0f, 0.0f, -40.0f }; + camera->getFrame()->translate(&t, rw::COMBINEPOSTCONCAT); + rw::V3d axis = { 0.0f, 1.0f, 0.0f }; + camera->getFrame()->rotate(&axis, 40.0f, rw::COMBINEPOSTCONCAT); + camera->setNearPlane(0.1f); + camera->setFarPlane(450.0f); + camera->setFOV(60.0f, 4.0f/3.0f); + world->addCamera(camera); + return 1; +} + +int +vsynch(int id) +{ + frames++; + ExitHandler(); + return 0; +} + +int +main() +{ + FlushCache(0); + if(!initrw()){ + printf("init failed!\n"); + for(;;); + } + + rw::uint32 len; + rw::uint8 *data = rw::getFileContents("host:player.DFF", &len); +// rw::uint8 *data = rw::getFileContents("host:od_newscafe_dy.dff", &len); + rw::StreamMemory in; + in.open(data, len); + rw::findChunk(&in, rw::ID_CLUMP, NULL, NULL); + rw::Clump *clump = rw::Clump::streamRead(&in); + in.close(); + delete[] data; + + GsCtx gsCtx; + + dmaReset(); + +// GsResetCrt(GS_NONINTERLACED, GS_NTSC, 0); +// GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32); + +// GsResetCrt(GS_INTERLACED, GS_NTSC, GS_FRAME); +// GsInitCtx(&gsCtx, 640, 224, GS_PSMCT32, GS_PSMZ32); + + GsResetCrt(GS_INTERLACED, GS_NTSC, GS_FIELD); + GsInitCtx(&gsCtx, WIDTH, HEIGHT, GS_PSMCT32, GS_PSMZ32); + + initrender(); + + AddIntcHandler(2, vsynch, 0); + EnableIntc(2); + + GsPutDrawCtx(&gsCtx.draw[0]); + GsPutDispCtx(&gsCtx.disp[1]); + // PCSX2 needs a delay for some reason + { int i; for(i = 0; i < 1000000; i++); } + clearscreen(0x80, 0x80, 0x80); +// drawtest(); +// drawtri(); + + camera->beginUpdate(); + beginCamera(); + FORLIST(lnk, clump->atomics) + drawAtomic(rw::Atomic::fromClump(lnk)); + camera->endUpdate(); + + printf("hello %p\n", clump); + for(;;); +// printf(""); + return 0; +} diff --git a/tools/ps2test/mem.h b/tools/ps2test/mem.h new file mode 100755 index 0000000..088c1d4 --- /dev/null +++ b/tools/ps2test/mem.h @@ -0,0 +1,95 @@ +/* FIFOs */ +#define VIF0_FIFO (*(volatile uint128*)0x10004000) +#define VIF1_FIFO (*(volatile uint128*)0x10005000) +#define GIF_FIFO (*(volatile uint128*)0x10006000) +#define IPU_out_FIFO (*(volatile uint128*)0x10007000) +#define IPU_in_FIFO (*(volatile uint128*)0x10007010) + +/* DMA channels */ +// to VIF0 +#define D0_CHCR (*(volatile uint32*)0x10008000) +#define D0_MADR (*(volatile uint32*)0x10008010) +#define D0_QWC (*(volatile uint32*)0x10008020) +#define D0_TADR (*(volatile uint32*)0x10008030) +#define D0_ASR0 (*(volatile uint32*)0x10008040) +#define D0_ASR1 (*(volatile uint32*)0x10008050) +// VIF1 +#define D1_CHCR (*(volatile uint32*)0x10009000) +#define D1_MADR (*(volatile uint32*)0x10009010) +#define D1_QWC (*(volatile uint32*)0x10009020) +#define D1_TADR (*(volatile uint32*)0x10009030) +#define D1_ASR0 (*(volatile uint32*)0x10009040) +#define D1_ASR1 (*(volatile uint32*)0x10009050) +// to GIF +#define D2_CHCR (*(volatile uint32*)0x1000a000) +#define D2_MADR (*(volatile uint32*)0x1000a010) +#define D2_QWC (*(volatile uint32*)0x1000a020) +#define D2_TADR (*(volatile uint32*)0x1000a030) +#define D2_ASR0 (*(volatile uint32*)0x1000a040) +#define D2_ASR1 (*(volatile uint32*)0x1000a050) +// fromIPU +#define D3_CHCR (*(volatile uint32*)0x1000b000) +#define D3_MADR (*(volatile uint32*)0x1000b010) +#define D3_QWC (*(volatile uint32*)0x1000b020) +// toIPU +#define D4_CHCR (*(volatile uint32*)0x1000b400) +#define D4_MADR (*(volatile uint32*)0x1000b410) +#define D4_QWC (*(volatile uint32*)0x1000b420) +#define D4_TADR (*(volatile uint32*)0x1000b430) +// from SIF0 +#define D5_CHCR (*(volatile uint32*)0x1000c000) +#define D5_MADR (*(volatile uint32*)0x1000c010) +#define D5_QWC (*(volatile uint32*)0x1000c020) +// to SIF1 +#define D6_CHCR (*(volatile uint32*)0x1000c400) +#define D6_MADR (*(volatile uint32*)0x1000c410) +#define D6_QWC (*(volatile uint32*)0x1000c420) +#define D6_TADR (*(volatile uint32*)0x1000c430) +// SIF2 +#define D7_CHCR (*(volatile uint32*)0x1000c800) +#define D7_MADR (*(volatile uint32*)0x1000c810) +#define D7_QWC (*(volatile uint32*)0x1000c820) +// fromSPR +#define D8_CHCR (*(volatile uint32*)0x1000d000) +#define D8_MADR (*(volatile uint32*)0x1000d010) +#define D8_QWC (*(volatile uint32*)0x1000d020) +#define D8_SADR (*(volatile uint32*)0x1000d080) +// toSPR +#define D9_CHCR (*(volatile uint32*)0x1000d400) +#define D9_MADR (*(volatile uint32*)0x1000d410) +#define D9_QWC (*(volatile uint32*)0x1000d420) +#define D9_TADR (*(volatile uint32*)0x1000d430) +#define D9_SADR (*(volatile uint32*)0x1000d480) + +/* DMA controller */ +#define D_CTRL (*(volatile uint32*)0x1000e000) +#define D_STAT (*(volatile uint32*)0x1000e010) +#define D_PCR (*(volatile uint32*)0x1000e020) +#define D_SQWC (*(volatile uint32*)0x1000e030) +#define D_RBSR (*(volatile uint32*)0x1000e040) +#define D_RBOR (*(volatile uint32*)0x1000e050) +#define D_STADR (*(volatile uint32*)0x1000e060) +#define D_ENABLER (*(volatile uint32*)0x1000f520) +#define D_ENABLEW (*(volatile uint32*)0x1000f590) + + +/* GS privileged registers */ +#define GS_PMODE (*(volatile uint64*)0x12000000) +#define GS_SMODE1 (*(volatile uint64*)0x12000010) +#define GS_SMODE2 (*(volatile uint64*)0x12000020) +#define GS_SRFSH (*(volatile uint64*)0x12000030) +#define GS_SYNCH1 (*(volatile uint64*)0x12000040) +#define GS_SYNCH2 (*(volatile uint64*)0x12000050) +#define GS_SYNCV (*(volatile uint64*)0x12000060) +#define GS_DISPFB1 (*(volatile uint64*)0x12000070) +#define GS_DISPLAY1 (*(volatile uint64*)0x12000080) +#define GS_DISPFB2 (*(volatile uint64*)0x12000090) +#define GS_DISPLAY2 (*(volatile uint64*)0x120000a0) +#define GS_EXTBUF (*(volatile uint64*)0x120000b0) +#define GS_EXTDATA (*(volatile uint64*)0x120000c0) +#define GS_EXTWRITE (*(volatile uint64*)0x120000d0) +#define GS_BGCOLOR (*(volatile uint64*)0x120000e0) +#define GS_CSR (*(volatile uint64*)0x12001000) +#define GS_IMR (*(volatile uint64*)0x12001010) +#define GS_BUSDIR (*(volatile uint64*)0x12001040) +#define GS_SIGLBLID (*(volatile uint64*)0x12001080) diff --git a/tools/ps2test/ps2.h b/tools/ps2test/ps2.h new file mode 100755 index 0000000..ced015a --- /dev/null +++ b/tools/ps2test/ps2.h @@ -0,0 +1,23 @@ +#include + +typedef int quad __attribute__((mode(TI))); +typedef int int128 __attribute__((mode(TI))); +typedef unsigned int uquad __attribute__((mode(TI))); +typedef unsigned int uint128 __attribute__((mode(TI))); + +#define MAKE128(RES,MSB,LSB) \ + __asm__ ( "pcpyld %0, %1, %2" : "=r" (RES) : "r" ((uint64)MSB), "r" ((uint64)LSB)) +#define UINT64(LOW,HIGH) (((uint64)HIGH)<<32 | ((uint64)LOW)) +#define MAKEQ(RES,W0,W1,W2,W3) MAKE128(RES,UINT64(W2,W3),UINT64(W0,W1)) + +#define BIT64(v,s) (((uint64)(v)) << (s)) + +#include "mem.h" +#include "gs.h" + +extern uint128 packetbuf[128]; + +void waitDMA(volatile uint32 *chcr); +void toGIF(void *src, int n); + +void drawcube(void); diff --git a/tools/ps2test/vu/defaultpipe.dsm b/tools/ps2test/vu/defaultpipe.dsm new file mode 100755 index 0000000..ae3fa39 --- /dev/null +++ b/tools/ps2test/vu/defaultpipe.dsm @@ -0,0 +1,93 @@ +.global defaultPipe + +.equ vertexTop, 0x3d0 +.equ numInAttribs, 4 +.equ numOutAttribs, 3 +.equ numOutBuf, 2 +.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf)) +.equ offset, (vertCount*numInAttribs) +.equ outBuf1, (2*offset) +.equ outSize, ((vertexTop-outBuf1-2)/2) +.equ outBuf2, (outBuf1+outSize) + +.equ lightMat, 0x3d0 +.equ ambientLight, 0x3d4 +.equ lightDir, 0x3d5 + +.equ matrix, 0x3f0 +.equ XYZScale, 0x3f7 +.equ XYZOffset, 0x3f8 +.equ gifTag, 0x3fa +.equ matColor, 0x3fb +.equ surfProps, 0x3fc + + +.balign 16,0 +defaultPipe: +DMAret * +MPG 0, * +.vu +Start: +#include "setup_persp.vu" +Cnt: + NOP XTOP VI02 ; input pointer + NOP LQ VF01, gifTag(VI00) + NOP XITOP VI01 ; vertex count + NOP IADDIU VI05, VI00, 0x4000 + NOP IADD VI05, VI05, VI05 + NOP IOR VI05, VI05, VI01 + NOP SQ VF01, 0(VI12) + NOP ISW.x VI05, 0(VI12) + NOP IADDIU VI03, VI12, 1 ; output pointer + NOP LQ VF18, lightMat(VI00) + NOP LQ VF19, lightMat+1(VI00) + NOP LQ VF20, lightMat+2(VI00) + +Loop: + NOP LQI VF01, (VI02++) ; vertex + NOP LQI VF02, (VI02++) ; UV + NOP LQI VF03, (VI02++) ; color + NOP LQI VF04, (VI02++) ; normal + + MULAw.xyzw ACC, VF31, VF00w NOP ; transform vertex + MADDAx.xyw ACC, VF28, VF01x NOP + MADDAy.xyw ACC, VF29, VF01y NOP + MADDz.xyzw VF01, VF30, VF01z NOP + ITOF0 VF03, VF03 NOP + ITOF0[I] VF04, VF04 LOI 0.0078125 ; - normal scale + NOP NOP + NOP DIV Q, VF00w, VF01w + NOP WAITQ + MULq VF01, VF01, Q NOP ; perspective division + MULi VF04, VF04, I NOP ; scale normal + NOP MR32.z VF02, VF00 + NOP NOP + SUB.w VF01, VF01, VF01 NOP + MULAx.xyz ACC, VF18, VF04x NOP ; transform normal + MADDAy.xyz ACC, VF19, VF04y NOP + MADDz.xyz VF04, VF20, VF04z NOP + ADD.xyz VF01, VF01, VF25 NOP + MULq VF02, VF02, Q NOP + NOP NOP + FTOI0 VF03, VF03 NOP + FTOI4 VF01, VF01 NOP + NOP SQ VF04, -2(VI02) ; store normal + NOP IADDI VI01, VI01, -1 + NOP SQI VF02, (VI03++) ; STQ + NOP SQI VF03, (VI03++) ; color + NOP SQI VF01, (VI03++) ; vertex + NOP IBNE VI01, VI00, Loop + NOP NOP + +#include "light.vu" + + NOP XGKICK VI12 + NOP IADD VI15,VI00,VI12 + NOP IADD VI12,VI00,VI13 + NOP[E] IADD VI13,VI00,VI15 + NOP NOP + NOP B Cnt + NOP NOP + +.EndMPG +.EndDmaData diff --git a/tools/ps2test/vu/light.vu b/tools/ps2test/vu/light.vu new file mode 100755 index 0000000..8f7a31c --- /dev/null +++ b/tools/ps2test/vu/light.vu @@ -0,0 +1,94 @@ +; Ambient light: + NOP LQ VF26, ambientLight(VI00) + NOP XITOP VI01 + NOP IADDIU VI03, VI12, 2 +Ambloop: + NOP LQ VF03, 0(VI03) ; output color + NOP NOP + NOP NOP + NOP NOP + ITOF0 VF03, VF03 NOP + NOP NOP + NOP NOP + NOP NOP + ADD.xyz VF03, VF03, VF26 NOP + NOP NOP + NOP NOP + NOP NOP + FTOI0 VF03, VF03 NOP + NOP IADDI VI01, VI01, -1 + NOP IADDIU VI03, VI03, numOutAttribs + NOP IBNE VI01, VI00, Ambloop + NOP SQ VF03, -numOutAttribs(VI03) +; end amblight + +; Direct Light + NOP LQ VF26, lightDir(VI00) + NOP XITOP VI01 + NOP XTOP VI02 + NOP IADDIU VI03, VI12, 2 + SUB.xyz VF26, VF00, VF26 NOP +Dirloop: + NOP LQ VF01, 3(VI02); ; normal + NOP LQ VF02, 0(VI03); ; output color + NOP NOP + NOP NOP + MUL VF03, VF01, VF26 NOP + ITOF0 VF02, VF02 NOP + NOP NOP + NOP NOP + ADDy.x VF03, VF03, VF03y NOP + NOP NOP + NOP NOP + NOP NOP + ADDz.x VF03, VF03, VF03z NOP + NOP NOP + NOP NOP + NOP NOP + MAX.x VF03, VF00, VF03 NOP ; clamp to 0 + NOP[I] LOI 255 + NOP NOP + NOP NOP + MULi.x VF03, VF03, I NOP + NOP NOP + NOP NOP + NOP NOP + ADDx.xyz VF02, VF02, VF03x NOP + NOP NOP + NOP NOP + NOP NOP + FTOI0 VF02, VF02 NOP + NOP IADDI VI01, VI01, -1 + NOP IADDIU VI02, VI02, numInAttribs + NOP IADDIU VI03, VI03, numOutAttribs + NOP IBNE VI01, VI00, Dirloop + NOP SQ VF02, -numOutAttribs(VI03) +; end dirlight + +; Material color and clamp + NOP LQ VF27, matColor(VI00) + NOP XITOP VI01 + NOP IADDIU VI03, VI12, 2 +Colorloop: + NOP LQ VF03, 0(VI03) + NOP NOP + NOP NOP + NOP NOP + ITOF0 VF03, VF03 NOP + NOP NOP + NOP NOP + NOP NOP + MUL VF03, VF03, VF27 NOP + NOP[I] LOI 255 + NOP NOP + NOP NOP + MINIi VF03, VF03, I NOP + NOP NOP + NOP NOP + NOP NOP + FTOI0 VF03, VF03 NOP + NOP IADDI VI01, VI01, -1 + NOP IADDIU VI03, VI03, numOutAttribs + NOP IBNE VI01, VI00, Colorloop + NOP SQ VF03, -numOutAttribs(VI03) +; end material color diff --git a/tools/ps2test/vu/setup_persp.vu b/tools/ps2test/vu/setup_persp.vu new file mode 100755 index 0000000..b9ea42f --- /dev/null +++ b/tools/ps2test/vu/setup_persp.vu @@ -0,0 +1,39 @@ +/* This is the the projection matrix we start with: + * 1/2w 0 ox/2w + 1/2 -ox/2w + * 0 -1/2h -oy/2h + 1/2 oy/2h + * 0 0 1 0 + * 0 0 1 0 + * To get rid of the +1/2 in the combined matrix we + * subtract the z-row/2 from the x- and y-rows. + * + * The z-row is then set to [0 0 0 1] such that multiplication + * by XYZscale gives [0 0 0 zScale]. After perspective division + * and addition of XYZoffset we then get zScale/w + zShift for z. + * + * XYZScale scales xy to the resolution and z by zScale. + * XYZOffset translates xy to the GS coordinate system (where + * [2048, 2048] is the center of the frame buffer) and add zShift to z. + */ + +; constant: +; VF28-VF31 transformation matrix +; VF25 XYZ offset + + + SUB.z VF28, VF28, VF28 LOI 0.5 ; right.z = 0 + SUB.z VF29, VF29, VF29 LQ VF28, matrix(VI00) ; up.z = 0 - load matrix + SUB.z VF30, VF30, VF30 LQ VF29, matrix+1(VI00) ; at.z = 0 - load matrix + ADDw.z VF31, VF00, VF00 LQ VF30, matrix+2(VI00) ; at.z = 1 - load matrix + NOP LQ VF31, matrix+3(VI00) ; - load matrix + MULi.w VF20, VF28, I LQ.xyz VF01, XYZScale(VI00) ; fix matrix - load scale + MULi.w VF21, VF29, I NOP ; fix matrix + MULi.w VF22, VF30, I NOP ; fix matrix + MULi.w VF23, VF31, I NOP ; fix matrix + SUBw.xy VF28, VF28, VF20 NOP ; fix matrix + SUBw.xy VF29, VF29, VF21 NOP ; fix matrix + SUBw.xy VF30, VF30, VF22 NOP ; fix matrix + SUBw.xy VF31, VF31, VF23 NOP ; fix matrix + MUL.xy VF28, VF28, VF01 LQ.xyz VF25, XYZOffset(VI00) ; scale matrix + MUL.xy VF29, VF29, VF01 IADDIU VI12, VI00, outBuf1 ; scale matrix + MUL.xy VF30, VF30, VF01 IADDIU VI13, VI00, outBuf2 ; scale matrix + MUL.xyz VF31, VF31, VF01 NOP ; scale matrix diff --git a/tools/ps2test/vu/skinpipe.dsm b/tools/ps2test/vu/skinpipe.dsm new file mode 100755 index 0000000..18536cd --- /dev/null +++ b/tools/ps2test/vu/skinpipe.dsm @@ -0,0 +1,94 @@ +.global skinPipe + +.equ vertexTop, 0x2d0 +.equ numInAttribs, 5 +.equ numOutAttribs, 3 +.equ numOutBuf, 2 +.equ vertCount, ((vertexTop-numOutBuf)/(numInAttribs*2+numOutAttribs*numOutBuf)) +.equ offset, (vertCount*numInAttribs) +.equ outBuf1, (2*offset) +.equ outSize, ((vertexTop-outBuf1-2)/2) +.equ outBuf2, (outBuf1+outSize) + +.equ lightMat, 0x3d0 +.equ ambientLight, 0x3d4 +.equ lightDir, 0x3d5 + +.equ matrix, 0x3f0 +.equ XYZScale, 0x3f7 +.equ XYZOffset, 0x3f8 +.equ gifTag, 0x3fa +.equ matColor, 0x3fb +.equ surfProps, 0x3fc + + +.balign 16,0 +skinPipe: +DMAret * +MPG 0, * +.vu +Start: +#include "setup_persp.vu" +Cnt: + NOP XTOP VI02 ; input pointer + NOP LQ VF01, gifTag(VI00) + NOP XITOP VI01 ; vertex count + NOP IADDIU VI05, VI00, 0x4000 + NOP IADD VI05, VI05, VI05 + NOP IOR VI05, VI05, VI01 + NOP SQ VF01, 0(VI12) + NOP ISW.x VI05, 0(VI12) + NOP IADDIU VI03, VI12, 1 ; output pointer + NOP LQ VF18, lightMat(VI00) + NOP LQ VF19, lightMat+1(VI00) + NOP LQ VF20, lightMat+2(VI00) + +Loop: + NOP LQI VF01, (VI02++) ; vertex + NOP LQI VF02, (VI02++) ; UV + NOP LQI VF03, (VI02++) ; color + NOP LQI VF04, (VI02++) ; normal + NOP IADDIU VI02, VI02, 1 ; skip weights + + MULAw.xyzw ACC, VF31, VF00w NOP ; transform vertex + MADDAx.xyw ACC, VF28, VF01x NOP + MADDAy.xyw ACC, VF29, VF01y NOP + MADDz.xyzw VF01, VF30, VF01z NOP + ITOF0 VF03, VF03 NOP + ITOF0[I] VF04, VF04 LOI 0.0078125 ; - normal scale + NOP NOP + NOP DIV Q, VF00w, VF01w + NOP WAITQ + MULq VF01, VF01, Q NOP ; perspective division + MULi VF04, VF04, I NOP ; scale normal + NOP MR32.z VF02, VF00 + NOP NOP + SUB.w VF01, VF01, VF01 NOP + MULAx.xyz ACC, VF18, VF04x NOP ; transform normal + MADDAy.xyz ACC, VF19, VF04y NOP + MADDz.xyz VF04, VF20, VF04z NOP + ADD.xyz VF01, VF01, VF25 NOP + MULq VF02, VF02, Q NOP + NOP NOP + FTOI0 VF03, VF03 NOP + FTOI4 VF01, VF01 NOP + NOP SQ VF04, -2(VI02) ; store normal + NOP IADDI VI01, VI01, -1 + NOP SQI VF02, (VI03++) ; STQ + NOP SQI VF03, (VI03++) ; color + NOP SQI VF01, (VI03++) ; vertex + NOP IBNE VI01, VI00, Loop + NOP NOP + +#include "light.vu" + + NOP XGKICK VI12 + NOP IADD VI15,VI00,VI12 + NOP IADD VI12,VI00,VI13 + NOP[E] IADD VI13,VI00,VI15 + NOP NOP + NOP B Cnt + NOP NOP + +.EndMPG +.EndDmaData