diff --git a/DanBias.sln b/DanBias.sln new file mode 100644 index 00000000..bf7eb41b --- /dev/null +++ b/DanBias.sln @@ -0,0 +1,165 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterGraphics", "OysterGraphics\OysterGraphics.vcxproj", "{0EC83E64-230E-48EF-B08C-6AC9651B4F82}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterMath", "OysterMath\OysterMath.vcxproj", "{F10CBC03-9809-4CBA-95D8-327C287B18EE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterPhysics3D", "OysterPhysics3D\OysterPhysics3D.vcxproj", "{4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sound", "Sound\Sound.vcxproj", "{34D6295A-00DD-4B1A-8258-97DA2818EC26}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowManager", "WindowManager\WindowManager.vcxproj", "{35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Input", "Input\Input.vcxproj", "{7E3990D2-3D94-465C-B58D-64A74B3ECF9B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Misc", "Misc\Misc.vcxproj", "{2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Network", "Network", "{C27B926E-B3EF-4990-8822-47580E43A0BE}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterNetworkClient", "Network\OysterNetworkClient\OysterNetworkClient.vcxproj", "{838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OysterNetworkServer", "Network\OysterNetworkServer\OysterNetworkServer.vcxproj", "{6A066806-F43F-4B31-A4E3-57179674F460}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetworkDependencies", "Network\NetworkDependencies\NetworkDependencies.vcxproj", "{C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Mixed Platforms = Release|Mixed Platforms + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Debug|Win32.ActiveCfg = Debug|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Debug|Win32.Build.0 = Debug|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Debug|x64.ActiveCfg = Debug|x64 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Debug|x64.Build.0 = Debug|x64 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Release|Mixed Platforms.Build.0 = Release|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Release|Win32.ActiveCfg = Release|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Release|Win32.Build.0 = Release|Win32 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Release|x64.ActiveCfg = Release|x64 + {0EC83E64-230E-48EF-B08C-6AC9651B4F82}.Release|x64.Build.0 = Release|x64 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Debug|Win32.Build.0 = Debug|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Debug|x64.ActiveCfg = Debug|x64 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Debug|x64.Build.0 = Debug|x64 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Release|Mixed Platforms.Build.0 = Release|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Release|Win32.ActiveCfg = Release|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Release|Win32.Build.0 = Release|Win32 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Release|x64.ActiveCfg = Release|x64 + {F10CBC03-9809-4CBA-95D8-327C287B18EE}.Release|x64.Build.0 = Release|x64 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Debug|Win32.ActiveCfg = Debug|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Debug|Win32.Build.0 = Debug|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Debug|x64.ActiveCfg = Debug|x64 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Debug|x64.Build.0 = Debug|x64 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Release|Mixed Platforms.Build.0 = Release|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Release|Win32.ActiveCfg = Release|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Release|Win32.Build.0 = Release|Win32 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Release|x64.ActiveCfg = Release|x64 + {4285BD3F-3C6C-4670-B7AF-A29AFEF5F6A8}.Release|x64.Build.0 = Release|x64 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Debug|Win32.ActiveCfg = Debug|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Debug|Win32.Build.0 = Debug|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Debug|x64.ActiveCfg = Debug|x64 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Debug|x64.Build.0 = Debug|x64 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Release|Mixed Platforms.Build.0 = Release|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Release|Win32.ActiveCfg = Release|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Release|Win32.Build.0 = Release|Win32 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Release|x64.ActiveCfg = Release|x64 + {34D6295A-00DD-4B1A-8258-97DA2818EC26}.Release|x64.Build.0 = Release|x64 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Debug|Win32.ActiveCfg = Debug|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Debug|Win32.Build.0 = Debug|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Debug|x64.ActiveCfg = Debug|x64 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Debug|x64.Build.0 = Debug|x64 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Release|Mixed Platforms.Build.0 = Release|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Release|Win32.ActiveCfg = Release|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Release|Win32.Build.0 = Release|Win32 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Release|x64.ActiveCfg = Release|x64 + {35AEA3C0-E0A7-4E1E-88CD-514AA5A442B1}.Release|x64.Build.0 = Release|x64 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Debug|Win32.ActiveCfg = Debug|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Debug|Win32.Build.0 = Debug|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Debug|x64.ActiveCfg = Debug|x64 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Debug|x64.Build.0 = Debug|x64 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Release|Mixed Platforms.Build.0 = Release|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Release|Win32.ActiveCfg = Release|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Release|Win32.Build.0 = Release|Win32 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Release|x64.ActiveCfg = Release|x64 + {7E3990D2-3D94-465C-B58D-64A74B3ECF9B}.Release|x64.Build.0 = Release|x64 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Debug|Win32.ActiveCfg = Debug|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Debug|Win32.Build.0 = Debug|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Debug|x64.ActiveCfg = Debug|x64 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Debug|x64.Build.0 = Debug|x64 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Release|Mixed Platforms.Build.0 = Release|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Release|Win32.ActiveCfg = Release|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Release|Win32.Build.0 = Release|Win32 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Release|x64.ActiveCfg = Release|x64 + {2EC4DDED-8F75-4C86-A10B-E1E8EB29F3EE}.Release|x64.Build.0 = Release|x64 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Debug|Win32.ActiveCfg = Debug|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Debug|Win32.Build.0 = Debug|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Debug|x64.ActiveCfg = Debug|x64 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Debug|x64.Build.0 = Debug|x64 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Release|Mixed Platforms.Build.0 = Release|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Release|Win32.ActiveCfg = Release|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Release|Win32.Build.0 = Release|Win32 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Release|x64.ActiveCfg = Release|x64 + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8}.Release|x64.Build.0 = Release|x64 + {6A066806-F43F-4B31-A4E3-57179674F460}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Debug|Win32.ActiveCfg = Debug|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Debug|Win32.Build.0 = Debug|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Debug|x64.ActiveCfg = Debug|x64 + {6A066806-F43F-4B31-A4E3-57179674F460}.Debug|x64.Build.0 = Debug|x64 + {6A066806-F43F-4B31-A4E3-57179674F460}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Release|Mixed Platforms.Build.0 = Release|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Release|Win32.ActiveCfg = Release|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Release|Win32.Build.0 = Release|Win32 + {6A066806-F43F-4B31-A4E3-57179674F460}.Release|x64.ActiveCfg = Release|x64 + {6A066806-F43F-4B31-A4E3-57179674F460}.Release|x64.Build.0 = Release|x64 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Debug|Mixed Platforms.Build.0 = Debug|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Debug|Win32.ActiveCfg = Debug|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Debug|Win32.Build.0 = Debug|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Debug|x64.ActiveCfg = Debug|x64 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Debug|x64.Build.0 = Debug|x64 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Release|Mixed Platforms.ActiveCfg = Release|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Release|Mixed Platforms.Build.0 = Release|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Release|Win32.ActiveCfg = Release|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Release|Win32.Build.0 = Release|Win32 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Release|x64.ActiveCfg = Release|x64 + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {838B25C2-D19E-49FE-8CB0-9A977CA3C7E8} = {C27B926E-B3EF-4990-8822-47580E43A0BE} + {6A066806-F43F-4B31-A4E3-57179674F460} = {C27B926E-B3EF-4990-8822-47580E43A0BE} + {C5AA09D0-6594-4CD3-BD92-1D380C7B3B50} = {C27B926E-B3EF-4990-8822-47580E43A0BE} + EndGlobalSection +EndGlobal diff --git a/Dokumentation/Danbias Structure.uxf b/Dokumentation/Danbias Structure.uxf new file mode 100644 index 00000000..f4c57a75 --- /dev/null +++ b/Dokumentation/Danbias Structure.uxf @@ -0,0 +1,428 @@ + + + 9 + + com.umlet.element.Class + + 675 + 342 + 108 + 27 + + Graphics + + + + com.umlet.element.Class + + 441 + 342 + 108 + 27 + + Sound + + + + com.umlet.element.Class + + 531 + 279 + 108 + 27 + + Physics / Math + + + + com.umlet.element.Class + + 684 + 153 + 99 + 27 + + Game client + + + + com.umlet.element.Class + + 351 + 279 + 126 + 27 + + Gamelogic + + + + com.umlet.element.Class + + 369 + 153 + 99 + 27 + + Game server + + + + com.umlet.element.Class + + 531 + 207 + 108 + 27 + + Network + + + + com.umlet.element.Class + + 558 + 342 + 108 + 27 + + Input + + + + com.umlet.element.Class + + 531 + 243 + 108 + 27 + + Threading + + + + com.umlet.element.Class + + 531 + 90 + 108 + 36 + + DanBias +bg=green + + + + com.umlet.element.Relation + + 702 + 153 + 44 + 206 + + lt=<- + 27;189;27;171;27;27 + + + com.umlet.element.Relation + + 459 + 153 + 287 + 206 + + lt=<- + 27;189;27;171;270;171;270;27 + + + com.umlet.element.Relation + + 387 + 153 + 44 + 143 + + lt=<- + 27;126;27;27 + + + com.umlet.element.Relation + + 612 + 153 + 134 + 152 + + lt=<- + 27;135;117;135;117;27 + + + com.umlet.element.Relation + + 387 + 153 + 161 + 80 + + lt=<- + 144;63;27;63;27;27 + + + com.umlet.element.Relation + + 450 + 261 + 98 + 44 + + lt=<- + 81;27;27;27 + + + com.umlet.element.Relation + + 585 + 153 + 161 + 206 + + lt=<- + 27;189;27;171;144;171;144;27 + + + com.umlet.element.Relation + + 387 + 153 + 161 + 116 + + lt=<- + 144;99;27;99;27;27 + + + com.umlet.element.Relation + + 612 + 153 + 134 + 116 + + lt=<- + 27;99;117;99;117;27 + + + com.umlet.element.Relation + + 612 + 153 + 134 + 80 + + lt=<- + 27;63;117;63;117;27 + + + com.umlet.element.Relation + + 612 + 72 + 134 + 98 + + lt=>- + 27;27;117;27;117;81 + + + com.umlet.element.Relation + + 387 + 72 + 161 + 98 + + lt=>- + 144;27;27;27;27;81 + + + com.umlet.element.Package + + 342 + 54 + 450 + 333 + + Game + + + + com.umlet.element.Relation + + 702 + 342 + 44 + 134 + + lt=<<. + 27;27;27;117 + + + com.umlet.element.Package + + 711 + 459 + 261 + 180 + + Graphics + + + + com.umlet.element.Class + + 720 + 486 + 243 + 144 + + <<interface>> +OysterGfx +-- +Init(InitData :struct) :enum state +NewFrame(FrameConstant :struct) :void +GatherData(Model :struct) :void +Render() :void +SetOptions(Options :struct) :void +LoadModel(file :const wchar[]) :Model* +Release(resource :Model*) :void + + + + com.umlet.element.Package + + 441 + 459 + 252 + 198 + + Input + + + + com.umlet.element.Relation + + 513 + 342 + 116 + 143 + + lt=<<. + 99;27;99;126;27;126 + + + com.umlet.element.Class + + 450 + 486 + 234 + 162 + + <<interface>> +RawInput +-- +Self() :RawInput* +Destroy() :void +QueryInput(Key :enum state(RIK)) :void +Subscribe(Callback :function) :void +Unsubscribe(Calback :function) :void +GetError() const :const wchar* +AddDevice(Data :struct) :enum state +Enable(Enable :bool) :void + + + + com.umlet.element.Class + + 351 + 342 + 81 + 27 + + Window API + + + + com.umlet.element.Relation + + 360 + 153 + 386 + 206 + + lt=<- + 27;189;27;171;369;171;369;27 + + + com.umlet.element.Package + + 126 + 459 + 306 + 198 + + Sound + + + + com.umlet.element.Class + + 135 + 486 + 288 + 99 + + <<interface>> +SoundWrapper +-- +LoadResource(file :const char*) :ResoureHandle* +Play(PlayData :struct) :InstanceID +Stop(InstanceID :int) :void +Release(Resource :ResourceHandle*) :void + + + + com.umlet.element.Class + + 135 + 612 + 288 + 36 + + <<API>> +-- +FMOD + + + + com.umlet.element.Relation + + 252 + 558 + 44 + 71 + + lt=<<. + 27;54;27;27 + + + com.umlet.element.Relation + + 216 + 342 + 296 + 143 + + lt=<<. + 279;27;279;72;207;72;207;126;27;126 + + diff --git a/Dokumentation/Other/FustrumCornerNormalsPseudoCode.txt b/Dokumentation/Other/FustrumCornerNormalsPseudoCode.txt new file mode 100644 index 00000000..348798f1 --- /dev/null +++ b/Dokumentation/Other/FustrumCornerNormalsPseudoCode.txt @@ -0,0 +1,16 @@ +float3 func( in float3 normalA, in float3 normalB, in float3 normalC ) +{ + return normalize( lerp( lerp(normalA, normalB, 0.5f), lerp(normalA, normalC, 0.5f), 0.5f ) ); + +} + +float3 nearTopLeft = func( f.topPlane.normal, f.leftPlane.normal, f.nearPlane.normal ); +float3 nearTopRight = func( f.topPlane.normal, f.rightPlane.normal, f.nearPlane.normal ); +float3 nearBottomLeft = func( f.bottomPlane.normal, f.leftPlane.normal, f.nearPlane.normal ); +float3 nearBottomRight = func( f.bottomPlane.normal, f.rightPlane.normal, f.nearPlane.normal ); + + +float3 farTopLeft = func( f.topPlane.normal, f.leftPlane.normal, f.farPlane.normal ); +float3 farTopRight = func( f.topPlane.normal, f.rightPlane.normal, f.farPlane.normal ); +float3 farBottomLeft = func( f.bottomPlane.normal, f.leftPlane.normal, f.farPlane.normal ); +float3 farBottomRight = func( f.bottomPlane.normal, f.rightPlane.normal, f.farPlane.normal ); diff --git a/Input/Dennis Input/InputCallbackHandler.cpp b/Input/Dennis Input/InputCallbackHandler.cpp new file mode 100644 index 00000000..be504df2 --- /dev/null +++ b/Input/Dennis Input/InputCallbackHandler.cpp @@ -0,0 +1,193 @@ +#include"RawInput.h" + + +//DefRawInputProc +//GetRawInputDeviceList +//GetRegisteredRawInputDevices + + + +LRESULT CALLBACK RawInput::WM_INPUT_TRANSLATE (int nCode, WPARAM wParam, LPARAM lparam) +{ + if (nCode < 0) return CallNextHookEx(RawInput::Self()->_msgHook, nCode, wParam, lparam); + + + MSG *m = (MSG*)lparam; + + if(m->message == WM_INPUT) + { + RAWINPUT* raw = RawInput::Self()->_TranslateRawInput(m->lParam); + + if(!raw) goto nextHook; + if(!RawInput::Self()->Self()->_enabled) + { + if(FAILED ( DefRawInputProc(&raw, 1, sizeof(RAWINPUTHEADER)) ) ) + RawInput::Self()->_errorMsg = L"Failed to proccess default raw input"; + goto _final; + } + // if(raw->header.dwType == RIM_TYPEMOUSE) RawInput::Self()->_idleMouseData.insert(raw->data.mouse); + //else if(raw->header.dwType == RIM_TYPEKEYBOARD) RawInput::Self()->_proccessRawKeyboardData(raw->data.keyboard); + + + _final: + + //if(FAILED ( DefRawInputProc(&raw, 1, sizeof(RAWINPUTHEADER)) ) ) + // RawInput::Self()->_errorMsg = L"Failed to proccess default raw input"; + + delete raw; + } + else if (m->message == WM_QUIT) + { + if(UnhookWindowsHookEx(RawInput::Self()->_msgHook) == FALSE) + { + RawInput::Self()->_errorMsg = L"Failed to unhook message hook!"; + } + } + + + nextHook: + return CallNextHookEx(RawInput::Self()->_msgHook, nCode, wParam, lparam); +} + + +RAWINPUT* RawInput::_TranslateRawInput (LPARAM l) +{ + //Get The size of the raw data buffer + UINT bufferSize; + GetRawInputData((HRAWINPUT)l, RID_INPUT, NULL, &bufferSize, sizeof(RAWINPUTHEADER)); + if (bufferSize < 1) + { + //Something went wrong + RawInput::Self()->_errorMsg = L"Failed to read raw buffer data in input class"; + return 0; + } + + //Create and read the raw input data + LPBYTE rawBufferIn = new BYTE[bufferSize]; + UINT readBytes = GetRawInputData((HRAWINPUT)l, RID_INPUT, rawBufferIn, &bufferSize, sizeof(RAWINPUTHEADER)); + if ( readBytes != bufferSize ) + { + RawInput::Self()->_errorMsg = L"Could not read raw input data"; + delete [] rawBufferIn; + return 0; + } + + return (RAWINPUT*)rawBufferIn; +} +void RawInput::_proccessRawKeyboardData (RAWKEYBOARD& k) +{ + if(!this->_KeyboardEnabled) return; + + //The key is released. + if(k.Flags == RI_KEY_BREAK || k.Flags == (RI_KEY_BREAK | RI_KEY_E0) || k.Flags == (RI_KEY_BREAK | RI_KEY_E1)) + { + if(k.Message == WM_SYSKEYUP) + { + // if(k.VKey == VK_CONTROL) this->_procCollection.skd.ctrl = false; + //else if(k.VKey == VK_MENU) this->_procCollection.skd.alt = false; + //else if(k.VKey == VK_SHIFT) this->_procCollection.skd.shift = false; + } + else if(k.Message == WM_KEYUP) + { + //this->_procCollection.kd.key = (RIK)k.VKey; + //this->_procCollection.kd.released = true; + } + } + //The key is pressed. + else if (k.Flags == RI_KEY_MAKE || k.Flags == (RI_KEY_MAKE | RI_KEY_E0) || k.Flags == (RI_KEY_MAKE | RI_KEY_E1)) + { + if(k.Message == WM_SYSKEYDOWN) + { + // if(k.VKey == VK_CONTROL) this->_procCollection.skd.ctrl = true; + //else if(k.VKey == VK_MENU) this->_procCollection.skd.alt = true; + //else if(k.VKey == VK_SHIFT) this->_procCollection.skd.shift = true; + } + else if(k.Message == WM_KEYDOWN) + { + //this->_procCollection.kd.key = (RIK)k.VKey; + //this->_procCollection.kd.released = false; + } + } +} +void RawInput::_proccessRawMouseData (RAWMOUSE& m) +{ + if(!this->_mouseEnabled) return; + + if(m.lLastX != 0 || m.lLastY != 0) + { + //this->_procCollection.mmd.MousePos_X += m.lLastX; + //this->_procCollection.mmd.MousePos_Y += m.lLastY; + } + if( m.usButtonFlags > 0 ) + { + + switch (m.usButtonFlags) + { + //Mouse button pressed + case RI_MOUSE_LEFT_BUTTON_DOWN: + case RI_MOUSE_RIGHT_BUTTON_DOWN: + case RI_MOUSE_MIDDLE_BUTTON_DOWN: + { + if(m.usButtonFlags == RI_MOUSE_LEFT_BUTTON_DOWN) + { + //MOUSE_INPUT_btnData.key = RIK_LeftBtn; + //LBTNDOWN = true; + } + else if(m.usButtonFlags == RI_MOUSE_MIDDLE_BUTTON_DOWN) + { + //MOUSE_INPUT_btnData.key = RIK_MiddleBtn; + //MBTNDOWN = true; + } + else if(m.usButtonFlags == RI_MOUSE_RIGHT_BUTTON_DOWN) + { + //MOUSE_INPUT_btnData.key = RIK_RightBtn; + //RBTNDOWN = true; + } + } + break; + + //Mouse button Released + case RI_MOUSE_LEFT_BUTTON_UP: + case RI_MOUSE_RIGHT_BUTTON_UP: + case RI_MOUSE_MIDDLE_BUTTON_UP: + { + if(m.usButtonFlags == RI_MOUSE_LEFT_BUTTON_UP) + { + //MOUSE_INPUT_btnData.key = RIK_LeftBtn; + //LBTNDOWN = false; + } + else if(m.usButtonFlags == RI_MOUSE_MIDDLE_BUTTON_UP) + { + //MOUSE_INPUT_btnData.key = RIK_MiddleBtn; + //MBTNDOWN = false; + } + else if(m.usButtonFlags == RI_MOUSE_RIGHT_BUTTON_UP) + { + //MOUSE_INPUT_btnData.key = RIK_RightBtn; + //RBTNDOWN = false; + } + } + break; + + case RI_MOUSE_WHEEL: + { + int d = ((int)m.usButtonData); + + if(d > 120) d = -1; + else d = 1; + + //this->_procCollection.wd = d; + } + break; + } + } +} + + + + + + + + + diff --git a/Input/Dennis Input/InputDeviceControll.cpp b/Input/Dennis Input/InputDeviceControll.cpp new file mode 100644 index 00000000..eb81da10 --- /dev/null +++ b/Input/Dennis Input/InputDeviceControll.cpp @@ -0,0 +1,57 @@ +#include "RawInput.h" + +void RawInput::Mouse_Show() +{ + +} +void RawInput::Mouse_Hide() +{ + +} +void RawInput::Mouse_Lock() +{ + +} +void RawInput::Mouse_Unlock() +{ + +} +void RawInput::Mouse_IsBtnPressed(IN RIK) +{ + +} +int RawInput::Mouse_WheelDelta() +{ + return 0; +} +POINT RawInput::Mouse_Position() +{ + POINT p = {0, 0}; + //POINT p = { this->_activeInputData.data.MOUSE_DATA.MousePos_X, this->_activeInputData.data.MOUSE_DATA.MousePos_Y }; + return p; +} + +void RawInput::Mouse_Enable() +{ + this->_mouseEnabled = true; +} +void RawInput::Mouse_Disable() +{ + this->_mouseEnabled = false; +} +bool RawInput::Keyboard_KeyUp(IN RIK key) +{ + return false; +} +bool RawInput::Keyboard_KeyDown(IN RIK key) +{ + return false; +} +void RawInput::Keyboard_Enable() +{ + this->_KeyboardEnabled = true; +} +void RawInput::Keyboard_Disable() +{ + this->_KeyboardEnabled = false; +} \ No newline at end of file diff --git a/Input/Dennis Input/InputSubscribe.cpp b/Input/Dennis Input/InputSubscribe.cpp new file mode 100644 index 00000000..6b59c090 --- /dev/null +++ b/Input/Dennis Input/InputSubscribe.cpp @@ -0,0 +1,142 @@ +#include "RawInput.h" + + +template +void SUBSCRIBE(SubscribeList* l, FNC _fnc, OBJECT_PARAM p) +{ + SubscribeList* t = new SubscribeList(); + + t->param = p; + t->fnc = _fnc; + t->next = l; + l = t; +} +template +void UNSUBSCRIBE(SubscribeList* l, FNC fnc) +{ + SubscribeList* w = l; + SubscribeList* p = 0; + while (w) + { + if(w->fnc == fnc) + { + if(p) + p->next = w->next; + + delete w; + w = 0; + } + else + { + p = w; + w = w->next; + } + } +} + + +void RawInput::Input_Subscribe (IN INPUT_CALLBACK fnc) +{ + //SUBSCRIBE(this->_procInput, fnc, &this->_procCollection.id); +} +void RawInput::Input_Unsubscribe (IN INPUT_CALLBACK fnc) +{ + //UNSUBSCRIBE(this->_procSystemKey, fnc); +} + + + + + + + + + + +/* +void RawInput::Subscribe (RAW_KEY_PROC fnc) +{ + KeyboardProcList* t = new KeyboardProcList(); + t->fnc = fnc; + t->next = 0; + + KeyboardProcList* w = this->_keyProcList; + KeyboardProcList* prev = this->_keyProcList; + + while (w) + { + prev = w; + w = w->next; + } + + prev->next = t; +} +void RawInput::Subscribe (RAW_MOUSE_PROC fnc) +{ + MouseProcList* t = new MouseProcList(); + t->fnc = fnc; + t->next = 0; + + MouseProcList* w = this->_mouseProcList; + MouseProcList* prev = this->_mouseProcList; + + while (w) + { + prev = w; + w = w->next; + } + + prev->next = t; +} +void RawInput::Unsubscribe (RAW_KEY_PROC fnc) +{ + KeyboardProcList* w = this->_keyProcList; + KeyboardProcList* prev = 0; + + while (w) + { + if(w->fnc == fnc) + { + if(prev) + prev->next = w->next; + + delete w; + w = 0; + } + else + { + prev = w; + w = w->next; + } + } +} +void RawInput::Unsubscribe (RAW_MOUSE_PROC fnc) +{ + MouseProcList* w = this->_mouseProcList; + MouseProcList* prev = 0; + + while (w) + { + if(w->fnc == fnc) + { + if(prev) + prev->next = w->next; + + delete w; + w = 0; + } + else + { + prev = w; + w = w->next; + } + } +} +*/ + + + + + + + diff --git a/Input/Dennis Input/InputSystem.cpp b/Input/Dennis Input/InputSystem.cpp new file mode 100644 index 00000000..77f5389c --- /dev/null +++ b/Input/Dennis Input/InputSystem.cpp @@ -0,0 +1,182 @@ +#include "RawInput.h" +#include +#include +#include + +#include +#include + + +static RawInput* gInstance = 0; + +template void DESTROY_LIST(SubscribeList* l) +{ + SubscribeList* w = l; + SubscribeList* p = 0; + + while (w) + { + p = w; + w = w->next; + delete p; + } +} +template void PROCESS_SUBSCRIBERS(SubscribeList* l) +{ + while (l) + { + l->fnc(l->param); + l = l->next; + } +} + + + + + + + + +RawInputWrapper* RawInputWrapper::Self () +{ + return (RawInputWrapper*)RawInput::Self(); +} +void RawInputWrapper::Destroy () +{ + RawInput::Destroy(); +} +RawInput* RawInput::Self () +{ + if(!gInstance) + gInstance = new RawInput(); + + return gInstance; +} +void RawInput::Destroy () +{ +/************************ Delete subscribers ****************************/ + DESTROY_LIST(RawInput::Self()->_procInput); + +/************************ Delete Other stuff ****************************/ + ShowCursor(true); + RECT r; + GetWindowRect(GetDesktopWindow(), &r); + ClipCursor(&r); + +/************************ Delete instance ****************************/ + delete gInstance; + gInstance = NULL; +} + + + + + +RawInput::RawInput () + : _procInput(0) + , _enabled(1) + , _mouseEnabled(1) + , _KeyboardEnabled(1) + , _exclusive(0) + , _errorMsg(0) + , _msgHook(SetWindowsHookEx(WH_GETMESSAGE, WM_INPUT_TRANSLATE, (HINSTANCE)0, GetCurrentThreadId())) +{ + if(!_msgHook) this->_errorMsg = L"Failed to initiate window message hook"; +} +RawInput::~RawInput () +{} + + +const wchar_t* RawInput::Input_GetError() const +{ + return this->_errorMsg; +} + +bool RawInput::Input_AddDevice(IN const HWND& targetApplication) +{ + assert(targetApplication != 0); + static const UINT c = 2; + RAWINPUTDEVICE devices[c] = + { + { 0x01, RawInput_Usage_keyboard, RIDEV_NOLEGACY, targetApplication }, + { 0x01, RawInput_Usage_mouse, RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE, targetApplication } + }; + + if(! _addDevice( devices , c ) ) return false; + + ShowCursor(FALSE); + //RECT r; + //GetWindow + //GetWindowRect( + + return true; +} +bool RawInput::Input_AddDevice(IN const RAWINPUTDEVICE* d, const int& count) +{ + for (int i = 0; i < count; i++) + if(!d[i].hwndTarget) + { + this->_errorMsg = L"Must specify target application"; + return false; + } + if(! _addDevice( d, count ) ) return false; + + return true; +} + +//RAWINPUTDEVICE d = { 0x01, type, RIDEV_REMOVE, NULL }; +//this->_errorMsg = L"Failed to unregister device"; + + +void RawInput::Input_Disable() +{ + this->_enabled = false; +} +void RawInput::Input_Enable() +{ + this->_enabled = true; +} + +void RawInput::Input_Read() +{ + //for (int i = 0; i < this->_idleKeyData.size(); i++) + // this->_proccessRawKeyboardData(this->_idleKeyData.pop()); + //for (int i = 0; i < this->_idleMouseData.size(); i++) + // this->_proccessRawMouseData(this->_idleMouseData.pop()); + // + //this->_idleKeyData.clear(); + //this->_idleMouseData.clear(); +} + + + + + + +bool RawInput::_addDevice (const RAWINPUTDEVICE* k, const int& count) +{ + if(RegisterRawInputDevices(k, count, sizeof(RAWINPUTDEVICE)) == FALSE) + { + DWORD h = GetLastError(); + this->_errorMsg = L"Failed to register device"; + return false; + } + + for (int q = 0; q < count; q++) + { + RawInputDeviceInstance i; + memcpy(&i.description, &k[q], sizeof(RAWINPUTDEVICE)); + this->_deviceList.push(i); + } + + return true; +} + + + + + + + + + diff --git a/Input/Dennis Input/Main.cpp b/Input/Dennis Input/Main.cpp new file mode 100644 index 00000000..bb355a6d --- /dev/null +++ b/Input/Dennis Input/Main.cpp @@ -0,0 +1,102 @@ +#include "RawInputWrapper.h" +// include the basic windows header file +#include +#include +#include +#include + + +HWND hWnd; +// this is the main message handler for the program +LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + // sort through and find what code to run for the message given + switch(message) + { + // this message is read when the window is closed + case WM_DESTROY: + { + // close the application entirely + PostQuitMessage(0); + return 0; + } break; + case WM_KEYUP: + MessageBox(0, L"WM_KEYUP", L"", 0); + break; + case WM_KEYDOWN: + MessageBox(0, L"WM_KEYDOWN", L"", 0); + break; + //case WM_INPUT: + // MessageBox(0, L"WM_INPUT_MAIN", L"", 0); + //break; + } + + // Handle any messages the switch statement didn't + return DefWindowProc (hWnd, message, wParam, lParam); +} +void initWindow(HINSTANCE h, int i) +{ + // this struct holds information for the window class + WNDCLASSEX wc; + + // clear out the window class for use + ZeroMemory(&wc, sizeof(WNDCLASSEX)); + + // fill in the struct with the needed information + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WindowProc; + wc.hInstance = h; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)COLOR_WINDOW; + wc.lpszClassName = L"WindowClass1"; + + // register the window class + RegisterClassEx(&wc); + + // create the window and use the result as the handle + hWnd = CreateWindowEx(NULL, + L"WindowClass1", // name of the window class + L"Our First Windowed Program", // title of the window + WS_OVERLAPPEDWINDOW, // window style + 300, // x-position of the window + 300, // y-position of the window + 500, // width of the window + 400, // height of the window + NULL, // we have no parent window, NULL + NULL, // we aren't using menus, NULL + h, // application handle + NULL); // used with multiple windows, NULL + + // display the window on the screen + ShowWindow(hWnd, i); +} +void initRaw() +{ + RawInputWrapper::Self()->Input_AddDevice(hWnd); +} +// the entry point for any Windows program +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + initWindow(hInstance, nCmdShow); + initRaw(); + + + // this struct holds Windows event messages + MSG msg; + + // wait for the next message in the queue, store the result in 'msg' + while(GetMessage(&msg, NULL, 0, 0)) + { + // translate keystroke messages into the right format + TranslateMessage(&msg); + // send the message to the WindowProc function + DispatchMessage(&msg); + + RawInputWrapper::Self()->Input_Read(); + } + + RawInputWrapper::Destroy(); + + return msg.wParam; +} \ No newline at end of file diff --git a/Input/Dennis Input/RawInput.h b/Input/Dennis Input/RawInput.h new file mode 100644 index 00000000..7f10a878 --- /dev/null +++ b/Input/Dennis Input/RawInput.h @@ -0,0 +1,104 @@ +#ifndef INCLUDE_GUARD_RAW_INPUT_H +#define INCLUDE_GUARD_RAW_INPUT_H + +#include "RawInputWrapper.h" +#include "misc.h" +#include + +/** +* TODO: +* 1. Origo in middle of the screen (-1 to 1) +*/ + + +//dx = +2*(x/w) -1 +//dx = -2*(y/h) +1 + +template +struct SubscribeList +{ + FNC fnc; + PARAM param; + SubscribeList* next; +}; +struct RawInputDeviceInstance +{ + RAWINPUTDEVICE description; +}; + + +enum RawInput_Usage +{ + RawInput_Usage_pointer = 1, + RawInput_Usage_mouse = 2, + RawInput_Usage_joystick = 4, + RawInput_Usage_gamepad = 5, + RawInput_Usage_keyboard = 6, + RawInput_Usage_keypad = 7, + RawInput_Usage_multiAxisController = 8, + RawInput_Usage_TabletPCcontrols = 9, +}; + +class RawInput :public RawInputWrapper +{ + private: + SubscribeList* _procInput; + + bool _enabled; + bool _mouseEnabled; + bool _KeyboardEnabled; + bool _exclusive; + const wchar_t* _errorMsg; + List _deviceList; + + List _mouseInput; + List _keyboardInput; + + HHOOK _msgHook; + + private: + RawInput (); + ~RawInput (); + + bool _addDevice (const RAWINPUTDEVICE* k, const int& count); + RAWINPUT*_TranslateRawInput (LPARAM l); + void _proccessRawMouseData (RAWMOUSE&); + void _proccessRawKeyboardData (RAWKEYBOARD&); + + static LRESULT CALLBACK WM_INPUT_TRANSLATE (int nCode, WPARAM wParam, LPARAM lParam); + + public: + + static RawInput* Self (); + static void Destroy (); + + const wchar_t* Input_GetError () const; + + bool Input_AddDevice (IN const HWND& targetApplication); + bool Input_AddDevice (IN const RAWINPUTDEVICE*, IN const int&); + + void Input_Subscribe (IN INPUT_CALLBACK fnc); + void Input_Unsubscribe (IN INPUT_CALLBACK fnc); + + void Input_Disable (); + void Input_Enable (); + + void Input_Read (); + + void Mouse_Show (); + void Mouse_Hide (); + void Mouse_Lock (); + void Mouse_Unlock (); + void Mouse_IsBtnPressed (IN RIK); + int Mouse_WheelDelta (); + POINT Mouse_Position (); + void Mouse_Enable (); + void Mouse_Disable (); + + bool Keyboard_KeyUp (IN RIK key); + bool Keyboard_KeyDown (IN RIK key); + void Keyboard_Enable (); + void Keyboard_Disable (); +}; +#endif + diff --git a/Input/Dennis Input/RawInputWrapper.h b/Input/Dennis Input/RawInputWrapper.h new file mode 100644 index 00000000..67389c89 --- /dev/null +++ b/Input/Dennis Input/RawInputWrapper.h @@ -0,0 +1,215 @@ +#ifndef RAW_INPUT_H +#define RAW_INPUT_H + +#include + + + +/*********************************************************************/ +/***************************** Keycodes ******************************/ +/*********************************************************************/ +//! Contains keycodes +enum RIK +{ + RIK_Backspace = 0x08, + RIK_Tab = 0x09, + RIK_Enter = 0x0D, + RIK_Shift = 0x10, + RIK_Ctrl = 0x11, + RIK_Alt = 0x12, + RIK_Pause = 0x13, + RIK_CapsLock = 0x14, + RIK_Escape = 0x1B, + RIK_Space = 0x20, + RIK_PgUp = 0x21, + RIK_PgDown = 0x22, + RIK_End = 0x23, + RIK_Home = 0x24, + RIK_Left = 0x25, + RIK_Up = 0x26, + RIK_Right = 0x27, + RIK_Down = 0x28, + RIK_PrintScreen = 0x2C, + RIK_Insert = 0x2D, + RIK_Delete = 0x2E, + RIK_0 = 0x30, + RIK_1 = 0x31, + RIK_2 = 0x32, + RIK_3 = 0x33, + RIK_4 = 0x34, + RIK_5 = 0x35, + RIK_6 = 0x36, + RIK_7 = 0x37, + RIK_8 = 0x38, + RIK_9 = 0x39, + RIK_A = 0x41, + RIK_B = 0x42, + RIK_C = 0x43, + RIK_D = 0x44, + RIK_E = 0x45, + RIK_F = 0x46, + RIK_G = 0x47, + RIK_H = 0x48, + RIK_I = 0x49, + RIK_J = 0x4A, + RIK_K = 0x4B, + RIK_L = 0x4C, + RIK_M = 0x4D, + RIK_N = 0x4E, + RIK_O = 0x4F, + RIK_P = 0x50, + RIK_Q = 0x51, + RIK_R = 0x52, + RIK_S = 0x53, + RIK_T = 0x54, + RIK_U = 0x55, + RIK_V = 0x56, + RIK_W = 0x57, + RIK_X = 0x58, + RIK_Y = 0x59, + RIK_Z = 0x5A, + RIK_LeftWindows = 0x5B, + RIK_RightWindows = 0x5C, + RIK_Numpad0 = 0x60, + RIK_Numpad1 = 0x61, + RIK_Numpad2 = 0x62, + RIK_Numpad3 = 0x63, + RIK_Numpad4 = 0x64, + RIK_Numpad5 = 0x65, + RIK_Numpad6 = 0x66, + RIK_Numpad7 = 0x67, + RIK_Numpad8 = 0x68, + RIK_Numpad9 = 0x69, + RIK_Multiply = 0x6A, + RIK_Plus = 0x6B, + RIK_Subtract = 0x6D, + RIK_Decimal = 0x6E, + RIK_Divide = 0x6F, + RIK_F1 = 0x70, + RIK_F2 = 0x71, + RIK_F3 = 0x72, + RIK_F4 = 0x73, + RIK_F5 = 0x74, + RIK_F6 = 0x75, + RIK_F7 = 0x76, + RIK_F8 = 0x77, + RIK_F9 = 0x78, + RIK_F10 = 0x79, + RIK_F11 = 0x7A, + RIK_F12 = 0x7B, + RIK_F13 = 0x7C, + RIK_F14 = 0x7D, + RIK_F15 = 0x7E, + RIK_F16 = 0x7F, + RIK_F17 = 0x80, + RIK_F18 = 0x81, + RIK_F19 = 0x82, + RIK_F20 = 0x83, + RIK_F21 = 0x84, + RIK_F22 = 0x85, + RIK_F23 = 0x86, + RIK_F24 = 0x87, + RIK_Numlock = 0x90, + RIK_ScrlLock = 0x91, + RIK_LeftShift = 0xA0, + RIK_RightShift = 0xA1, + RIK_LeftCtrl = 0xA2, + RIK_RightCtrl = 0xA3, + + COUNT +}; +enum RIM +{ + RIM_LeftBtn = 0x02, + RIM_MiddleBtn = 0x10, + RIM_RightBtn = 0x04, + RIM_Scroll = 0x0400, +}; +/*********************************************************************/ + + +/**************************************************************************/ +/***************************** Callback data ******************************/ +/**************************************************************************/ +enum InputType +{ + InputType_Keyboard, + InputType_Mouse, + InputType_HID, +}; +struct RawMouseData +{ + bool shift; + bool alt; + bool ctrl; + + RIM key; + bool pressed; + + int MousePos_X; + int MousePos_Y; + + int delta; +}; +struct RawKeyData +{ + bool shift; + bool alt; + bool ctrl; + + RIK key; + bool released; +}; +struct RawInputData +{ + InputType type; + union + { + RawMouseData MOUSE_DATA; + RawKeyData KEYBOARD_DATA; + RAWHID HID_DATA; + } data; +}; +typedef void(*INPUT_CALLBACK)(const RawInputData*); +/*********************************************************************/ + +class RawInputWrapper +{ + public: + static RawInputWrapper* Self (); + static void Destroy (); + + virtual const wchar_t* Input_GetError () const PURE; + + virtual bool Input_AddDevice (IN const HWND& targetApplication) PURE; + virtual bool Input_AddDevice (IN const RAWINPUTDEVICE* d, IN const int& count) PURE; + + virtual void Input_Subscribe (IN INPUT_CALLBACK fnc) PURE; + virtual void Input_Unsubscribe (IN INPUT_CALLBACK fnc) PURE; + + virtual void Input_Disable () PURE; + virtual void Input_Enable () PURE; + + virtual void Input_Read () PURE; + + virtual void Mouse_Show () PURE; + virtual void Mouse_Hide () PURE; + virtual void Mouse_Lock () PURE; + virtual void Mouse_Unlock () PURE; + virtual void Mouse_IsBtnPressed (IN RIK key) PURE; + virtual int Mouse_WheelDelta () PURE; + virtual POINT Mouse_Position () PURE; + virtual void Mouse_Enable () PURE; + virtual void Mouse_Disable () PURE; + + virtual bool Keyboard_KeyUp (IN RIK key) PURE; + virtual bool Keyboard_KeyDown (IN RIK key) PURE; + virtual void Keyboard_Enable () PURE; + virtual void Keyboard_Disable () PURE; + + +}; + + +#endif + diff --git a/Input/Dennis Input/misc.h b/Input/Dennis Input/misc.h new file mode 100644 index 00000000..f9c76deb --- /dev/null +++ b/Input/Dennis Input/misc.h @@ -0,0 +1,120 @@ +#ifndef MISC_H +#define MISC_H + + +#include + + +template +class List +{ + private: + class Node + { + public: + T value; + Node *next; + Node(T value){ this->value = value; this->next = NULL; } + ~Node() {} + }; + + Node *first; + int nrOfNodes; + + public: + List::List() + { + this->first = NULL; + this->nrOfNodes = 0; + } + + List::~List() + { + Node *walker = this->first; + + for(int i = 0; inrOfNodes; i++) + { + walker = walker->next; + delete this->first; + this->first = walker; + } + } + + List& List::operator=(const List& origObj) + { + if(this->nrOfNodes > 0) + { + Node *walker = this->first; + + for(int i = 0; inrOfNodes; i++) + { + walker = walker->next; + delete this->first; + this->first = walker; + } + } + + this->nrOfNodes = 0; + if(origObj.nrOfNodes > 0) + { + Node *walker = origObj.first; + + for(int i = 0; ivalue); + walker = walker->next; + } + } + + return *this; + } + + void List::push(T value) + { + Node *e = new Node(value); + e->next = this->first; + this->first = e; + e = NULL; + this->nrOfNodes++; + } + + T List::pop() + { + T removed; + memset(&removed, 0, sizeof(T)); + + if(this->nrOfNodes > 0) + { + Node *temp = first; + this->first = first->next; + memcpy(&removed, &temp->value, sizeof(T)); + delete temp; + this->nrOfNodes--; + } + + return removed; + } + + int List::size() const + { + return this->nrOfNodes; + } + + void clear() + { + Node *w = this->first; + Node *p = 0; + while (w) + { + p = w; + w = w->next; + delete p; + } + + this->first = 0; + } + +}; + + +#endif diff --git a/Input/InputController.cpp b/Input/InputController.cpp new file mode 100644 index 00000000..d534a073 --- /dev/null +++ b/Input/InputController.cpp @@ -0,0 +1,284 @@ +#include "InputController.h" +using namespace Oyster::Input; + +namespace +{ + bool keys[256] = {0}; + bool prevs[256]= {0}; + bool mouse[5] = {0}; + bool mPrev[5] = {0}; + int XPos,YPos,PrevX,PrevY,DeltaX,DeltaY; +} + +void Controller::KeyPressed(const WPARAM &Key) +{ + prevs[Key]=false; + keys[Key]=true; +} + +void Controller::KeyReleased(const WPARAM &Key) +{ + prevs[Key]=true; + keys[Key] = false; +} + +bool Controller::isKeyDown(const WPARAM &Key) +{ + return keys[Key]; +} + +bool Controller::isKeyPressed(const WPARAM &Key) +{ + if(keys[Key] && !prevs[Key]) + { + prevs[Key] = keys[Key]; + return true; + } + return false; +} + +bool Controller::isKeyReleased(const WPARAM &Key) +{ + if(!keys[Key] && prevs[Key]) + { + prevs[Key] = keys[Key]; + return true; + } + return false; +} + +void Controller::MouseBtnPressed(const WPARAM &btn) +{ + switch(btn) + { + case MK_LBUTTON: + mouse[0] = true; + mPrev[0] = false; + break; + case MK_RBUTTON: + mouse[1] = true; + mPrev[1] = false; + break; + case MK_MBUTTON: + mouse[2] = true; + mPrev[2] = false; + break; + case MK_XBUTTON1: + mouse[3] = true; + mPrev[3] = false; + break; + case MK_XBUTTON2: + mouse[4] = true; + mPrev[4] = false; + break; + } +} + +void Controller::MouseBtnReleased(const WPARAM &btn) +{ + switch(btn) + { + case MK_LBUTTON: + mouse[0] = false; + mPrev[0] = true; + break; + case MK_RBUTTON: + mouse[1] = false; + mPrev[1] = true; + break; + case MK_MBUTTON: + mouse[2] = false; + mPrev[2] = true; + break; + case MK_XBUTTON1: + mouse[3] = false; + mPrev[3] = true; + break; + case MK_XBUTTON2: + mouse[4] = false; + mPrev[4] = true; + break; + } +} + + +bool Controller::isMouseBtnDown(const WPARAM &Btn) +{ + switch(Btn) + { + case MK_LBUTTON: + return mouse[0]; + case MK_RBUTTON: + return mouse[1]; + case MK_MBUTTON: + return mouse[2]; + case MK_XBUTTON1: + return mouse[3]; + case MK_XBUTTON2: + return mouse[4]; + } + + return false; +} + +bool Controller::isMouseBtnPressed(const WPARAM &Btn) +{ + switch(Btn) + { + case MK_LBUTTON: + if(mouse[0] && !mPrev[0]) + { + mPrev[0] = mouse[0]; + return true; + } + return false; + case MK_RBUTTON: + if(mouse[1] && !mPrev[1]) + { + mPrev[1] = mouse[1]; + return true; + } + return false; + case MK_MBUTTON: + if(mouse[2] && !mPrev[2]) + { + mPrev[2] = mouse[2]; + return true; + } + return false; + case MK_XBUTTON1: + if(mouse[3] && !mPrev[3]) + { + mPrev[3] = mouse[3]; + return true; + } + return false; + case MK_XBUTTON2: + if(mouse[4] && !mPrev[4]) + { + mPrev[4] = mouse[4]; + return true; + } + return false; + } + + return false; +} + +bool Controller::isMouseBtnReleased(const WPARAM &Btn) +{ + switch(Btn) + { + case MK_LBUTTON: + if(!mouse[0] && mPrev[0]) + { + mPrev[0] = mouse[0]; + return true; + } + return false; + case MK_RBUTTON: + if(!mouse[1] && mPrev[1]) + { + mPrev[1] = mouse[1]; + return true; + } + return false; + case MK_MBUTTON: + if(!mouse[2] && mPrev[2]) + { + mPrev[2] = mouse[2]; + return true; + } + return false; + case MK_XBUTTON1: + if(!mouse[3] && mPrev[3]) + { + mPrev[3] = mouse[3]; + return true; + } + return false; + case MK_XBUTTON2: + if(!mouse[4] && mPrev[4]) + { + mPrev[4] = mouse[4]; + return true; + } + return false; + } + + return false; +} + +void Controller::MouseMove(int x,int y) +{ + PrevY = YPos; + PrevX = XPos; + XPos = x; + YPos = y; + DeltaY = YPos - PrevY; + DeltaX = XPos - PrevX; +} + +int Controller::GetY() +{ + return YPos; +} + +int Controller::GetX() +{ + return XPos; +} + +float Controller::GetAnalogX() +{ + float f = (float)XPos; + f /=( Window::Size.left/2); + return f; +} + +float Controller::GetAnalogY() +{ + float f = (float)YPos; + f /=( Window::Size.top/2); + return f; +} + +int Controller::GetDeltaY() +{ + return DeltaY; +} + +int Controller::GetDeltaX() +{ + return DeltaX; +} + +void Controller::ResetDeltaX() +{ + DeltaX = 0; +} + +void Controller::ResetDeltaY() +{ + DeltaY = 0; +} + +void Controller::RestrictMouse(bool restrict) +{ + Oyster::Window::CaptureMouse(restrict); +} + +//sets x=0,y=0 to be the center oc the client area +void Controller::OrigoCenter() +{ + int x = Window::Size.left/2; + int y = Window::Size.top/2; + + Window::SetMouseOffset(-x,-y); +} + +//default +void Controller::OrigoTopLeft() +{ + Oyster::Window::SetMouseOffset(0,0); +} \ No newline at end of file diff --git a/Input/InputController.h b/Input/InputController.h new file mode 100644 index 00000000..5b4292c6 --- /dev/null +++ b/Input/InputController.h @@ -0,0 +1,63 @@ +#pragma once + +#ifndef InputController_H +#define InputController_H + +#include "../Window/Window.h" +//READ http://msdn.microsoft.com/en-us/library/windows/desktop/ms648380(v=vs.85).aspx#_win32_Confining_a_Cursor + +namespace Oyster +{ + class Window; + namespace Input + { + class Controller + { + friend class ::Oyster::Window; + private: + //Keybord events from Oyster::Window + static void KeyPressed(const WPARAM &Key); + //Keybord events from Oyster::Window + static void KeyReleased(const WPARAM &Key); + + + //Mouse events from Oyster::Window + static void MouseMove(int x,int y); + //Mouse events from Oyster::Window + static void MouseBtnPressed(const WPARAM &Btn); + static void MouseBtnReleased(const WPARAM &Btn); + public: + //Polling Functions + static bool isKeyDown(const WPARAM &Key); + static bool isKeyPressed(const WPARAM &Key); + static bool isKeyReleased(const WPARAM &Key); + + static bool isMouseBtnDown(const WPARAM &Btn); + static bool isMouseBtnPressed(const WPARAM &Btn); + static bool isMouseBtnReleased(const WPARAM &Btn); + + static int GetX(); + static int GetY(); + + static float GetAnalogX(); + static float GetAnalogY(); + + static int GetDeltaX(); + static int GetDeltaY(); + + //Controll Functions + static void ResetDeltaX(); + static void ResetDeltaY(); + + //off by default + static void RestrictMouse(bool b = true); + + //sets x=0,y=0 to be the center oc the client area + static void OrigoCenter(); + + //default + static void OrigoTopLeft(); + }; + } +} +#endif \ No newline at end of file diff --git a/Misc/Utilities.cpp b/Misc/Utilities.cpp new file mode 100644 index 00000000..c3046aeb --- /dev/null +++ b/Misc/Utilities.cpp @@ -0,0 +1,216 @@ +///////////////////////////////////////////////////////////////////// +// Utility Collection of Miscellanious Handy Functions +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Utilities.h" +#include +#include + +using ::std::vector; +using ::std::string; + +namespace Utility +{ +// PRIVATE STATIC //////////////////////////////////////////////////// + namespace PrivateStatic + { + const ::std::locale systemDefaultLocale = ::std::locale(); + } + +// STRING //////////////////////////////////////////////////////////// + namespace String + { + vector & split( vector &output, const string &str, char delim, string::size_type offset ) + { + if( str.length() > 0 ) + { + while( offset < str.length() ) // trim + { + if( str[offset] == delim ) + ++offset; + else break; + } + + string::size_type delimPos = str.find_first_of( delim, offset ); + if( delimPos == string::npos ) + { + if( str.length() > offset ) + output.push_back( str.substr( offset, str.length() - offset ) ); + } + else + { + if( delimPos > offset ) + output.push_back( str.substr( offset, delimPos - offset ) ); + String::split( output, str, delim, delimPos + 1 ); + } + } + return output; + } + + vector & split( vector &output, const string &str, const string &delim, string::size_type offset ) + { + if( str.length() > 0 ) + { + string::size_type delimPos = str.find_first_of( delim, offset ); + if( delimPos == string::npos ) + { + if( str.length() > offset ) + output.push_back( str.substr( offset, str.length() - offset ) ); + } + else + { + if( delimPos > offset ) + output.push_back( str.substr( offset, delimPos - offset ) ); + String::split( output, str, delim, delimPos + delim.length() ); + } + } + return output; + } + + vector & split( vector &output, const string &str, const vector &delim, string::size_type offset ) + { + if( str.length() > 0 ) + { + string::size_type firstDelimPos = str.length(), delimPos; + + vector::size_type numDelims = delim.size(), delimRef = 0; + for( vector::size_type i = 0; i < numDelims ; ++i ) + { + delimPos = str.find_first_of( delim[i], offset ); + if( delimPos != string::npos ) if( delimPos < firstDelimPos ) + { + delimRef = i; + firstDelimPos = delimPos; + } + } + + if( firstDelimPos == str.length() ) + { + if( str.length() > offset ) + output.push_back( str.substr( offset, str.length() - offset ) ); + } + else + { + if( firstDelimPos > offset ) + output.push_back( str.substr( offset, firstDelimPos - offset ) ); + String::split( output, str, delim, firstDelimPos + delim[delimRef].length() ); + } + } + return output; + } + + string trim( const string &str ) + { + string::size_type first = 0, + last = str.length(); + + if( last == 0 ) return str; + + while( first < last ) + { + if( str[first] == ' ' || str[first] == '\t' || str[first] == '\r' || str[first] == '\n' ) + ++first; + else break; + } + + --last; + while( last > first ) + { + if( str[last] == ' ' || str[last] == '\t' || str[last] == '\r' || str[last] == '\n' ) + --last; + else break; + } + + if( first == last ) if( str[first] == ' ' || str[first] == '\t' || str[first] == '\r' || str[first] == '\n' ) + return ""; + + return str.substr( first, (++last) - first ); + } + + string & toLowerCase( string &output, const string &str ) + { + int length = (int)str.length(); + output.resize( length ); + for( int i = 0; i < length; ++i ) + output[i] = ::std::tolower( str[i], ::std::locale() ); + return output; + } + + string & toLowerCase( string &str ) + { + int length = (int)str.length(); + for( int i = 0; i < length; ++i ) + str[i] = ::std::tolower( str[i], ::std::locale() ); + return str; + } + + string & toUpperCase( string &output, const string &str ) + { + int length = (int)str.length(); + output.resize( length ); + for( int i = 0; i < length; ++i ) + output[i] = ::std::toupper( str[i], ::std::locale() ); + return output; + } + + string & toUpperCase( string &str ) + { + int length = (int)str.length(); + for( int i = 0; i < length; ++i ) + str[i] = ::std::toupper( str[i], ::std::locale() ); + return str; + } + + string & extractDirPath( string &output, const string &file, char dirDelimeter ) + { + string d = " "; + d[0] = dirDelimeter; + return String::extractDirPath( output, file, d ); + } + + string & extractDirPath( string &output, const string &file, const string &dirDelimeter ) + { + string::size_type end = file.find_last_of( dirDelimeter ); + if( end == string::npos ) + output = ""; + else + { + ++end; + output.resize( end ); + for( string::size_type i = 0; i < end; ++i ) + output[i] = file[i]; + } + + return output; + } + + string & replaceCharacters( string &str, char characterToReplace, char newCharacter, const string::size_type &offset, const string::size_type &end ) + { + string::size_type i = offset; + while( true ) + { + i = str.find_first_of( characterToReplace, i ); + if( i >= end ) break; + + str[i++] = newCharacter; + } + return str; + } + } + + // STREAM //////////////////////////////////////////////////////////// + namespace Stream + { + float* readFloats( float *output, ::std::istream &input, unsigned int numFloats ) + { + string str; + for( unsigned int i = 0; i < numFloats; ++i ) + { + input >> str; + output[i] = (float)::std::atof( str.c_str() ); + } + return output; + } + } +} \ No newline at end of file diff --git a/Misc/Utilities.h b/Misc/Utilities.h new file mode 100644 index 00000000..aa9128c3 --- /dev/null +++ b/Misc/Utilities.h @@ -0,0 +1,80 @@ +///////////////////////////////////////////////////////////////////// +// Utility Collection of Miscellanious Handy Functions +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef UTILITIES_H +#define UTILITIES_H + +#include +#include +#include +#include + +namespace Utility +{ + namespace String + { + // note to self: add a whitespaceSplit method? + ::std::vector<::std::string> & split( ::std::vector<::std::string> &output, const ::std::string &str, char delim, ::std::string::size_type offset = 0 ); + ::std::vector<::std::string> & split( ::std::vector<::std::string> &output, const ::std::string &str, const ::std::string &delim, ::std::string::size_type offset = 0 ); + ::std::vector<::std::string> & split( ::std::vector<::std::string> &output, const ::std::string &str, const ::std::vector<::std::string> &delim, ::std::string::size_type offset = 0 ); + ::std::string trim( const ::std::string &str ); + ::std::string & toLowerCase( ::std::string &output, const ::std::string &str ); + ::std::string & toLowerCase( ::std::string &str ); + ::std::string & toUpperCase( ::std::string &output, const ::std::string &str ); + ::std::string & toUpperCase( ::std::string &str ); + ::std::string & extractDirPath( ::std::string &output, const ::std::string &file, char dirDelimeter ); + ::std::string & extractDirPath( ::std::string &output, const ::std::string &file, const ::std::string &dirDelimeter ); + ::std::string & replaceCharacters( ::std::string &str, char characterToReplace, char newCharacter, const ::std::string::size_type &offset = 0, const ::std::string::size_type &end = ::std::string::npos ); + } + + namespace Stream + { + float* readFloats( float *output, ::std::istream &input, unsigned int numFloats ); + } + + namespace StaticArray + { + template + inline unsigned int numElementsOf( const ElementType(&)[num] ) + { return num; } + } + + namespace Element + { + template + inline void swap( ElementType &elementA, ElementType &elementB, ElementType &swapSpace ) + { swapSpace = elementA; elementA = elementB; elementB = swapSpace; } + + template + inline void swap( ElementType &elementA, ElementType &elementB ) + { ElementType swapSpace; swap( elementA, elementB, swapSpace ); } + } + + namespace Value + { + template + inline ValueType abs( const ValueType &value ) + { return value < 0 ? value * -1 : value; } + + template + inline ValueType max( const ValueType &valueA, const ValueType &valueB ) + { return valueA > valueB ? valueA : valueB; } + + template + inline ValueType min( const ValueType &valueA, const ValueType &valueB ) + { return valueA < valueB ? valueA : valueB; } + + template + inline ValueType radian( const ValueType °ree ) + { return degree * (3.1415926535897932384626433832795f / 180.0f); } + + template + inline ValueType degree( const ValueType &radian ) + { return radian * (180.0f / 3.1415926535897932384626433832795f); } + } +} + +#endif \ No newline at end of file diff --git a/Misc/WinTimer.cpp b/Misc/WinTimer.cpp new file mode 100644 index 00000000..d8ccfbb2 --- /dev/null +++ b/Misc/WinTimer.cpp @@ -0,0 +1,75 @@ +#include "WinTimer.h" + +using namespace ::Utility; + +namespace PrivateStatic +{ + LARGE_INTEGER ticksPerSecond = { 0 }; + double secondsPerTick = 0.0f; + + class WatchDog + { + public: + WatchDog( ) + { + if( QueryPerformanceFrequency( &ticksPerSecond ) > 0 ) + secondsPerTick = ((double)1.0f) / (double) ticksPerSecond.QuadPart; + } + } watchDog; +} + +WinTimer::WinTimer( ) : isPaused(false) +{ this->reset(); } + +void WinTimer::reset( ) +{ + this->isPaused = false; + this->pauseCount.QuadPart = 0; + QueryPerformanceCounter( &this->startTick ); +} + +void WinTimer::pause( ) +{ + if( !this->isPaused ) + { + this->isPaused = true; + QueryPerformanceCounter( &this->pauseStart ); + } +} + +void WinTimer::resume( ) +{ + if( this->isPaused ) + { + this->isPaused = false; + LARGE_INTEGER currentTick; + QueryPerformanceCounter( ¤tTick ); + this->pauseCount.QuadPart += currentTick.QuadPart - this->pauseStart.QuadPart; + } +} + +double WinTimer::getElapsedSeconds( ) const +{ + if( this->isPaused ) + { + LARGE_INTEGER totalTick = this->pauseStart; + totalTick.QuadPart -= this->startTick.QuadPart; + totalTick.QuadPart -= this->pauseCount.QuadPart; + return PrivateStatic::secondsPerTick * (double)totalTick.QuadPart; + } + else + { + LARGE_INTEGER currentTick; + QueryPerformanceCounter( ¤tTick ); + currentTick.QuadPart -= this->startTick.QuadPart; + currentTick.QuadPart -= this->pauseCount.QuadPart; + return PrivateStatic::secondsPerTick * (double)currentTick.QuadPart; + } +} + +LARGE_INTEGER WinTimer::getCurrentTick( ) const +{ + LARGE_INTEGER currentTick; + QueryPerformanceCounter( ¤tTick ); + return currentTick; +} \ No newline at end of file diff --git a/Misc/WinTimer.h b/Misc/WinTimer.h new file mode 100644 index 00000000..73e9091f --- /dev/null +++ b/Misc/WinTimer.h @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////// +// Instanciable Timer class for windows +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef WINTIMER_H +#define WINTIMER_H + +#include + +namespace Utility +{ + class WinTimer + { + public: + WinTimer( ); + + void reset( ); + void pause( ); + void resume( ); + + double getElapsedSeconds( ) const; + LARGE_INTEGER getCurrentTick( ) const; + + private: + LARGE_INTEGER startTick, pauseStart, pauseCount; + bool isPaused; + }; +} + +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/Event.cpp b/Network/NetworkDependencies/Event.cpp new file mode 100644 index 00000000..33e92bbf --- /dev/null +++ b/Network/NetworkDependencies/Event.cpp @@ -0,0 +1,262 @@ +#include "Event.h" +using namespace Event; + + +//---------------------------- +// BulletCreated class definitions +BulletCreated::BulletCreated(int ownerID, Float3 position, Float3 direction) + : + GameEvent() +{ + data.owner=ownerID; + data.head=direction; +} +void BulletCreated::LoadRawData(char* d) +{ + memcpy(&data, d, GetSize()); + /*int offset=0; + memcpy(&data.position, data, sizeof(Float3)); + offset+=sizeof(Float3); + + memcpy(&data.head, d+offset, sizeof(Float3)); + offset+=sizeof(Float3); + memcpy(&data.owner, d+offset, sizeof(int));*/ +} +void BulletCreated::SaveRawData(char* d) +{ + memcpy(d, &data, GetSize()); +} + +//---------------------------- +// BulletHit class definitions +BulletHit::BulletHit(int attacker, int hitPlayer) + : + GameEvent() +{ + data.hitTarget=hitPlayer; + data.attackingTarget=attacker; + //this->hpLeft=hl; + //this->shieldLeft=sl; +} +void BulletHit::LoadRawData(char* d) +{ + memcpy(&data, d, GetSize()); +} +void BulletHit::SaveRawData(char* d) +{ + memcpy(d, &data, GetSize()); +} + +ScoreUpdate::ScoreUpdate(Score* scores) +{ + for (int i=0; iGetSize()); + /*int offset=0; + memcpy(&data.position, data, sizeof(Float3)); + offset+=sizeof(Float3); + + memcpy(&playerID, data+offset, sizeof(int));*/ +} +void ShipSpawned::SaveRawData(char* d) +{ + memcpy(d, &data, GetSize()); +} + + +//---------------------------- +// GameEnded class definitions +GameEnded::GameEnded() + : + GameEvent() +{ +} +GameEnded::GameEnded(int winner) + : + GameEvent() +{ + data.winningTeam=winner; +} +void GameEnded::LoadRawData(char* d) +{ + memcpy(&data, d, GetSize()); + /*int offset=0; + memcpy(&eventPosition, data, sizeof(Float3)); + offset+=sizeof(Float3); + + memcpy(&winningTeam, data+offset, sizeof(int)); + offset+=sizeof(int); + + for (int i=0; i +#include +#include +#include +#include +#include +#include +#include + +#include "OysterMath.h" +using namespace Oyster::Math; + +//ws2_32.lib is a lib file the linker requires for winsock compilation +#pragma comment(lib, "Ws2_32.lib") +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkInitStructs.h b/Network/NetworkDependencies/NetworkInitStructs.h new file mode 100644 index 00000000..7ef04ed1 --- /dev/null +++ b/Network/NetworkDependencies/NetworkInitStructs.h @@ -0,0 +1,70 @@ +#ifndef NET_INIT_STRUCTS_H +#define NET_INIT_STRUCTS_H +#include "NetworkIncludes.h" +#include "NetworkConstants.h" +struct PlayerInitStruct +{ + INT8 pid; + int teamid; + Oyster::Math::Float4x4 position; + PlayerInitStruct() + { + pid=0; + //position=Oyster::Math::Float4x4::identity; + } +}; + +struct GameInitData +{ + INT8 pid; + //std::string playerNames[PLAYER_MAX_COUNT]; + PlayerInitStruct player[PLAYER_MAX_COUNT]; +}; + +struct LobbyUserStruct +{ + INT8 pid; + INT8 shipID; + char usrName[15]; + LobbyUserStruct() + { + pid=0; + shipID=0; + usrName[0]='\0'; + } + void setName(const char* n) + { + strcpy_s(usrName, n); + } + int size() + { + int sz=sizeof(pid); + sz+=sizeof(shipID); + int tmp=(int)strlen(usrName); + sz+=(int)strlen(usrName); + return sz; + } +}; +struct LobbyInitData +{ + INT8 pid; + INT8 playerCount; + int timer; + LobbyUserStruct players[PLAYER_MAX_COUNT]; + LobbyInitData() + { + pid=0; + for (int i=0; i splitString(const char* p_inStr, char p_delim) +{ + std::stringstream ss(p_inStr); + std::vector elems; + std::string item; + while(std::getline(ss, item, p_delim)) + { + elems.push_back(item); + } + return elems; +} \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkMiscFunctions.h b/Network/NetworkDependencies/NetworkMiscFunctions.h new file mode 100644 index 00000000..a6959020 --- /dev/null +++ b/Network/NetworkDependencies/NetworkMiscFunctions.h @@ -0,0 +1,9 @@ +#ifndef NET_MISC_FNC_H +#define NET_MISC_FNC_H +#include +#include +#include +std::vector splitString(const char* p_inStr, char p_delim); +#define SSTR( x ) dynamic_cast< std::ostringstream & >( \ + ( std::ostringstream() << std::dec << x ) ).str() +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkTimer.cpp b/Network/NetworkDependencies/NetworkTimer.cpp new file mode 100644 index 00000000..42b8a143 --- /dev/null +++ b/Network/NetworkDependencies/NetworkTimer.cpp @@ -0,0 +1,85 @@ +#include "NetworkTimer.h" +NetworkTimer::NetworkTimer() + : + c_SecondsPerCount(0.0), + c_DeltaTime(-1.0), + c_BaseTime(0), + c_PausedTime(0), + c_PrevTime(0), + c_CurrTime(0), + c_Stopped(false) +{ + __int64 countsPerSec; + QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); + c_SecondsPerCount =1.0 / (double)countsPerSec; + + QueryPerformanceCounter((LARGE_INTEGER*)&c_PrevTime); +} + +void NetworkTimer::start() +{ + __int64 p_StartTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_StartTime); + if(c_Stopped) + { + c_PausedTime += (p_StartTime-c_StopTime); + c_PrevTime = p_StartTime; + c_StopTime = 0; + c_Stopped = false; + } +} +__int64 NetworkTimer::getTime() +{ + __int64 testInt; + return QueryPerformanceCounter((LARGE_INTEGER*)&testInt); + return testInt; +} + +void NetworkTimer::stop() +{ + if(!c_Stopped) + { + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_StopTime = p_CurrTime; + c_Stopped = true; + } +} +void NetworkTimer::reset() +{ + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_BaseTime = p_CurrTime; + c_PrevTime = p_CurrTime; + c_StopTime = 0; + c_Stopped = false; +} +void NetworkTimer::tick() +{ + if (c_Stopped) + { + c_DeltaTime= 0.0; + return; + } + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_CurrTime=p_CurrTime; + + c_DeltaTime=(c_CurrTime-c_PrevTime)*c_SecondsPerCount; + c_PrevTime=c_CurrTime; + if(c_DeltaTime<0.0) c_DeltaTime=0.0; +} +float NetworkTimer::getGameTime() const +{ + if(c_Stopped) + { + return (float)((c_StopTime-c_BaseTime)*c_SecondsPerCount); + } else + { + return (float)(((c_CurrTime-c_PausedTime)-c_BaseTime)*c_SecondsPerCount); + } +} +float NetworkTimer::getDeltaTime() const +{ + return (float)c_DeltaTime; +} \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkTimer.h b/Network/NetworkDependencies/NetworkTimer.h new file mode 100644 index 00000000..c4581c50 --- /dev/null +++ b/Network/NetworkDependencies/NetworkTimer.h @@ -0,0 +1,25 @@ +#include "NetworkIncludes.h" +#ifndef _NET_TIMER_H +#define _NET_TIMER_H +class NetworkTimer +{ +private: + double c_SecondsPerCount; + double c_DeltaTime; + __int64 c_BaseTime; + __int64 c_PausedTime; + __int64 c_StopTime; + __int64 c_PrevTime; + __int64 c_CurrTime; + bool c_Stopped; +public: + NetworkTimer(); + __int64 getTime(); + void start(); + void stop(); + void reset(); + void tick(); + float getGameTime() const; + float getDeltaTime() const; +}; +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/NetworkUpdateStructs.h b/Network/NetworkDependencies/NetworkUpdateStructs.h new file mode 100644 index 00000000..97f2037d --- /dev/null +++ b/Network/NetworkDependencies/NetworkUpdateStructs.h @@ -0,0 +1,62 @@ +#ifndef NET_UPD_STRUCTS_H +#define NET_UPD_STRUCTS_H +#include "NetworkIncludes.h" +namespace Network +{ + struct EffectData + { + int identifier; + Float3 head; + Float3 tail; + }; + struct ServerToClientUpdateData + { + int pid; + Oyster::Math::Float4x4 position; + float dirVecLen; + int hp; + int shield; + long updateCount; + ServerToClientUpdateData() + { + pid=0; + updateCount=0; + hp=0; + shield=0; + } + }; + const int SERVER_PLAYER_DATA_SIZE = 84; + struct ClientToServerUpdateData + { + __int8 pid; + //Oyster::Math::Float4x4 position; + __int8 forward; + __int8 roll; + __int8 straferight; + __int8 strafeup; + bool firePrim; + bool fireSecond; + bool fireSpecial; + long updateCount; + bool braking; + float TurnHor; + float TurnVer; + ClientToServerUpdateData() + { + pid=0; + forward=0; + roll=0; + straferight=0; + strafeup=0; + firePrim=false; + fireSecond=false; + fireSpecial=false; + updateCount=0; + braking=false; + TurnHor= 0.0f; + TurnVer= 0.0f; + } + }; + const int CLIENT_PLAYER_DATA_SIZE = sizeof(ClientToServerUpdateData); +} +#endif \ No newline at end of file diff --git a/Network/NetworkDependencies/UpdateStructs.cpp b/Network/NetworkDependencies/UpdateStructs.cpp new file mode 100644 index 00000000..05209a9c --- /dev/null +++ b/Network/NetworkDependencies/UpdateStructs.cpp @@ -0,0 +1 @@ +#include "NetworkUpdateStructs.h" \ No newline at end of file diff --git a/Network/OysterNetworkClient/ClientDataHandler.cpp b/Network/OysterNetworkClient/ClientDataHandler.cpp new file mode 100644 index 00000000..52d0f2ff --- /dev/null +++ b/Network/OysterNetworkClient/ClientDataHandler.cpp @@ -0,0 +1,112 @@ +#include "SocketClient.h" + +#pragma once +#ifndef SOCKET_DATA_CPP +#define SOCKET_DATA_CPP + +/*std::vector splitString(char* p_inStr, char p_delim) +{ +std::stringstream ss(p_inStr); +std::vector elems; +std::string item; +while(std::getline(ss, item, p_delim)) +{ +elems.push_back(item); +} +return elems; +}*/ + +void SocketClient::parseReceivedData(/*char* data, int size*/) +{ + switch (recvBuffer[0]) // TODO: runtime error occured here when shutting down client. recvBuffer invalid pointer. ~Dan 2013-05-14 + { + case 1://It's data + parseData(); + break; + case 2://For the moment, this is only for init data + parseGameInitData(); + break; + case 3://It's a chat message + parseMessage(); + break; + case 4://It's a server message + parseServermessage(); + break; + case 5://Player has been connected to a game lobby + parseLobbyInitData(); + break; + case 6://It's an event + parseReceivedEvent(); + break; + case 7: + parseReceivedEffect(); + break; + case 8: + parseRenderData(); + break; + default: + int a=0; + + } +} +void SocketClient::parseRenderData() +{ + receiveRenderData(recvBuffer+1, recvBufLen-1); +} +void SocketClient::parseReceivedEffect() +{ + receiveEffectData(recvBuffer+1, recvBufLen-1); +} +void SocketClient::parseReceivedEvent() +{ + receiveEvent(recvBuffer+1); +} +void SocketClient::parseGameInitData() +{ + receiveGameInitData(recvBuffer+1); + connectStatus=true; +} + +void SocketClient::parseLobbyInitData() +{ + receiveLobbyInitData(recvBuffer+1, recvBufLen-1); + connectStatus=true; +} + +void SocketClient::parseServermessage() +{ + recvBuffer[recvBufLen]='\0'; + if(!strcmp(recvBuffer+1, "connected")) + { + connectStatus=true; + connStatus=ONLINE_MAINMENU; + receiveConnStatus(ONLINE_MAINMENU); + } + else if(!strcmp(recvBuffer+1, "qst")) + { + connStatus=ONLINE_QUEUEING; + receiveConnStatus(ONLINE_QUEUEING); + } + else if(!strcmp(recvBuffer+1, "qed")) + { + connStatus=ONLINE_MAINMENU; + receiveConnStatus(ONLINE_MAINMENU); + } + //Server message of some sort +} + +void SocketClient::parseData() +{ + //memcpy(&tmpPlayer,buffer+1,playerDataSize); + //playerContPtr->setPlayerStruct(tmpPlayer); + receivePlayerUpdate(recvBuffer+1, recvBufLen-1); +} + +void SocketClient::parseMessage() +{ + //std::string message; + //message="[Chat] "+users[pid].getUsername()+": "+(buffer+1); + printf("%s\n",recvBuffer+1); +} + +#endif diff --git a/Network/OysterNetworkClient/ClientInitFunctions.cpp b/Network/OysterNetworkClient/ClientInitFunctions.cpp new file mode 100644 index 00000000..e2c4b920 --- /dev/null +++ b/Network/OysterNetworkClient/ClientInitFunctions.cpp @@ -0,0 +1,79 @@ +#include "SocketClient.h" + +#pragma once +#ifndef SOCKET_INIT_CPP +#define SOCKET_INIT_CPP + +bool SocketClient::startReceiveThread() +{ + threadhandle[0]=CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)&receiveDataThreadV, + (LPVOID) this, + 0, + NULL); + return true; +} + +bool SocketClient::startSendDataThread() +{ + threadhandle[1]=CreateThread( + NULL, + 0, + (LPTHREAD_START_ROUTINE)&receiveDataThreadV, + (LPVOID) this, + 0, + NULL); + return true; +} +bool SocketClient::init(int listenPort) +{ + return initUDPSocket(listenPort); +} +bool SocketClient::connectToIP(const char* ip, int listenPort, char* initData, int initDataSize) +{ + init(listenPort); + //--------------------------------------------- + // Set up the port and IP of the server + //Port starts up as a different one from when connected, it changes once the server has exchanged some info with the client + + UDPsendAddr.sin_family = AF_INET; + UDPsendAddr.sin_port = htons(UDPSendPort); + UDPsendAddr.sin_addr.s_addr = inet_addr(ip); + + TCPsendAddr.sin_family = AF_INET; + TCPsendAddr.sin_port = htons(TCPSendPort); + TCPsendAddr.sin_addr.s_addr = inet_addr(ip); + /*iResult=connect(connTCP, (SOCKADDR *) &TCPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + int test=WSAGetLastError(); + wprintf(L"connect failed with error: %d\n", WSAGetLastError()); + //closesocket(connTCP); + //WSACleanup(); + return false; + }/* + iResult=send(connTCP, initData, initDataSize, 0); + if (iResult == SOCKET_ERROR) { + int test=WSAGetLastError(); + wprintf(L"connect failed with error: %d\n", WSAGetLastError()); + //closesocket(connTCP); + //WSACleanup(); + return false; + }*/ + + iResult = sendto(connUDP, + initData, initDataSize, 0, (SOCKADDR *) & UDPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"Client UDP sendto failed with error: %d\n", WSAGetLastError()); + //closesocket(connUDP); + //WSACleanup(); + return false; + } + //connectStatus=true; + connectStatus=false; + return true; +} + + +#endif diff --git a/Network/OysterNetworkClient/ClientMain.cpp b/Network/OysterNetworkClient/ClientMain.cpp new file mode 100644 index 00000000..5c297686 --- /dev/null +++ b/Network/OysterNetworkClient/ClientMain.cpp @@ -0,0 +1,79 @@ +#include "SocketClient.h" +const int maxThreadCount=2; +bool validateIpAddress(const std::string ipAddress) +{ + struct sockaddr_in sa; + int result = inet_pton(AF_INET, ipAddress.c_str(), &(sa.sin_addr)); + return result != 0; +} +/*int main(int argc, char *argv[]) +{ + std::string tst; + bool test=true; + //Multithreading variables + //int nThreads = 0; + //DWORD dwThreadId[maxThreadCount]; + //HANDLE threadhandle; + + GameClass game; + SocketClient client; + //Sets up the link to the GameClass class. + client.setPlayerContPtr(&game); + //This is the loop which makes the user enter the server address. + while (!client.isReady()); + do + { + if (!test) + { + printf("Could not connect to server. Try another IP.\n"); + } + else + { + printf("Enter the server ip. \n"); + } + getline(std::cin, tst); + if (tst.length()==0) + { + tst="127.0.0.1"; + } + if (validateIpAddress(tst)) + { + //Tmp init connection message: set username + char* tmp=new char[30]; + printf("What is your desired username?\n"); + std::cin.getline(tmp,30); + if (strlen(tmp)==0) + { + tmp="Anonymous"; + } + printf("Username set to %s\n", tmp); + + test=client.connectToIP(tst.c_str(), tmp, strlen(tmp)); + } + else + { + printf("Invalid IPaddress. Please enter a new IPaddress.\n"); + test=false; + } + } while (!test); + while (!client.isConnected()); + Sleep(1000); + //Starts the receive loop + //threadhandle=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)&client.receiveDataThreadV,(LPVOID) &client,0,&dwThreadId[0]); + client.startReceiveThread(); + //GetExitCodeThread(threadhandle, eCode); + //This is just a loop to receive user input which creates a natural delay for sendUserData. + printf("Write what you want to send\n"); + tst="tmp init message"; + while (tst.length()>0) + { + client.sendMessage(tst); + client.sendUserData(); + getline(std::cin, tst); + } + //Kills off the thread and connection + //DWORD eCode=0; + //TerminateThread(threadhandle, eCode); + client.closeConnection(); + return 0; +}*/ \ No newline at end of file diff --git a/Network/OysterNetworkClient/ClientTCPSpecific.cpp b/Network/OysterNetworkClient/ClientTCPSpecific.cpp new file mode 100644 index 00000000..1e8b7216 --- /dev/null +++ b/Network/OysterNetworkClient/ClientTCPSpecific.cpp @@ -0,0 +1,39 @@ +#include "SocketClient.h" + +bool SocketClient::initTCPSocket(int listenPort) +{ + TCPrecvAddr.sin_family = AF_INET; + TCPrecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + TCPrecvAddr.sin_port = htons(/*TCPRecvPort*/listenPort); + + connTCP = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (connTCP == INVALID_SOCKET) + { + wprintf(L"socket function failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + + iResult = bind(connTCP, (SOCKADDR *) & TCPrecvAddr, addrSize); + if (iResult == SOCKET_ERROR) + { + int tst=WSAGetLastError(); + wprintf(L"bind function failed with error %d\n", WSAGetLastError()); + iResult = closesocket(connTCP); + if (iResult == SOCKET_ERROR) + wprintf(L"closesocket function failed with error %d\n", WSAGetLastError()); + //WSACleanup(); + return false; + } + return true; +} +bool SocketClient::sendDataTCP(const char* data, int size) +{ + iResult = sendto(connTCP, + data, size, 0, (SOCKADDR *) & TCPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"TCP sendto failed with error: %d\n", WSAGetLastError()); + return false; + } + return true; +} \ No newline at end of file diff --git a/Network/OysterNetworkClient/ClientUDPSpecific.cpp b/Network/OysterNetworkClient/ClientUDPSpecific.cpp new file mode 100644 index 00000000..9cab63ae --- /dev/null +++ b/Network/OysterNetworkClient/ClientUDPSpecific.cpp @@ -0,0 +1,39 @@ +#include "SocketClient.h" +bool SocketClient::initUDPSocket(int listenPort) +{ + UDPrecvAddr.sin_family = AF_INET; + UDPrecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + UDPrecvAddr.sin_port = htons(listenPort); + //--------------------------------------------- + // Create a socket for sending data + connUDP = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (connUDP == INVALID_SOCKET) + { + wprintf(L"socket failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + iResult = bind(connUDP, (SOCKADDR *) & UDPrecvAddr, addrSize); + if (iResult == SOCKET_ERROR) + { + wprintf(L"bind function failed with error %d\n", WSAGetLastError()); + iResult = closesocket(connUDP); + if (iResult == SOCKET_ERROR) + wprintf(L"closesocket function failed with error %d\n", WSAGetLastError()); + WSACleanup(); + return false; + } + return true; +} +bool SocketClient::sendDataUDP(const char* data, int size) +{ + iResult = sendto(connUDP, + data, size, 0, (SOCKADDR *) & UDPsendAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"sendto failed with error: %d\n", WSAGetLastError()); + //closesocket(connUDP); + //WSACleanup(); + return false; + } + return true; +} \ No newline at end of file diff --git a/Network/OysterNetworkClient/SocketClient.cpp b/Network/OysterNetworkClient/SocketClient.cpp new file mode 100644 index 00000000..cde039cf --- /dev/null +++ b/Network/OysterNetworkClient/SocketClient.cpp @@ -0,0 +1,133 @@ +#include "SocketClient.h" +#pragma once +#ifndef SOCKET_CLIENT_CPP +#define SOCKET_CLIENT_CPP + +SocketClient::SocketClient() +{ + playerDataSize=Network::CLIENT_PLAYER_DATA_SIZE; + sendDelayMS=10; + connUDP = INVALID_SOCKET; + connTCP = INVALID_SOCKET; + //sendBuffer=new char[BUFFER_MAX_SIZE]; + //sendBufLen=BUFFER_MAX_SIZE; + //ZeroMemory(sendBuffer,sendBufLen); + recvBuffer=new char[BUFFER_MAX_SIZE]; + recvBufLen=BUFFER_MAX_SIZE; + ZeroMemory(recvBuffer,recvBufLen); + + dataBuf=new char[playerDataSize+1]; + dataBuf[0]=1; + //ZeroMemory(b,sizeof(buffer)); + //---------------------- + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (iResult != NO_ERROR) { + printf("WSAStartup failed with error: %d\n", iResult); + } + + + + addrSize=sizeof(sockaddr_in); + connectStatus=false; +} + + + +bool SocketClient::sendUserData() +{ + //memcpy(dataBuf+1,&playerContPtr->getPlayerData(),playerDataSize); + //return sendData(dataBuf, playerDataSize+1); + printf("NOT YET IMPLEMENTED"); + return false; +} + +bool SocketClient::sendUserData(char* data, int size) +{ + memcpy(dataBuf+1,data,size); + return sendDataUDP(dataBuf, size+1); +} + +bool SocketClient::sendMessage(std::string msg) +{ + if (msg[0]=='/') + { + //Server command + msg[0]=2; + + } + else + { + //Chat message + msg='1'+msg; + msg[0]=3; + } + return sendDataUDP(msg.c_str(), (int)msg.size()); +} + +bool SocketClient::closeConnection() +{ + connectStatus=false; + Sleep(5); + //Give the threads 5 ms to quit themselves before terminating them + DWORD eCode=0; + TerminateThread(threadhandle[0], eCode); + TerminateThread(threadhandle[1], eCode); + //--------------------------------------------- + // When the application is finished sending, close the socket. + setupStatus=false; + printf("Finished sending. Closing socket.\n"); + iResult = closesocket(connUDP); + if (iResult == SOCKET_ERROR) + { + wprintf(L"closesocket failed with error: %d\n", WSAGetLastError()); + WSACleanup(); + return false; + } + //--------------------------------------------- + // Clean up and quit. + printf("Exiting.\n"); + WSACleanup(); + return true; +} + +void SocketClient::receiveDataThreadV(SocketClient* ptr) +{ + while(true) + { + ptr->recvBufLen=recvfrom(ptr->connUDP, ptr->recvBuffer, BUFFER_MAX_SIZE, 0, (SOCKADDR *) & ptr->UDPsendAddr, &ptr->addrSize); + if (ptr->recvBufLen == SOCKET_ERROR) + { + wprintf(L"recv failed with error %d\n", WSAGetLastError()); + } + //ptr->buffer[ptr->iResult]='\0'; + else + ptr->parseReceivedData(); + } +} + + +void SocketClient::receiveDataWaitOnResponse() +{ + recvBufLen=recvfrom(connUDP, recvBuffer, BUFFER_MAX_SIZE, 0, (SOCKADDR *) & UDPsendAddr, &addrSize); + if (recvBufLen == SOCKET_ERROR) + { + wprintf(L"recv failed with error %d\n", WSAGetLastError()); + } + //buffer[iResult]='\0'; + else + parseReceivedData(); +} + +void SocketClient::sendDataThreadV(SocketClient* ptr) +{ + printf("NOT YET IMPLEMENTED"); + /*while(ptr->connectStatus) + { + memcpy(ptr->dataBuf+1,&ptr->playerContPtr->getPlayerData(),playerDataSize); + ptr->sendData(ptr->dataBuf, playerDataSize+1); + Sleep(ptr->sendDelayMS); + }*/ +} + +#endif \ No newline at end of file diff --git a/Network/OysterNetworkClient/SocketClient.h b/Network/OysterNetworkClient/SocketClient.h new file mode 100644 index 00000000..46c57d8d --- /dev/null +++ b/Network/OysterNetworkClient/SocketClient.h @@ -0,0 +1,147 @@ +#pragma once +//Start by defining unicode +//#ifndef UNICODE +//#define UNICODE +//#endif +//defining WIN32_LEAN_AND_MEAN this early is REQUIRED if you want to avoid a certain winsock error. +//#define WIN32_LEAN_AND_MEAN +//#define NOMINMAX +//#include +//#include "GameClassExample.h" +//These includes are required for winsock +#include "Network.h" +//#include +//#include +//#include +//#include +//#include "OysterMath.h" +//These are optional includes for various useful features +#include +#include +#include +#include + +//ws2_32.lib is a lib file the linker requires for winsock compilation +#pragma comment(lib, "Ws2_32.lib") + +//constants used by the socket client to avoid hard coding and/or mass variable declaration +const short TCPSendPort = 11110; +const short TCPRecvPort = 11111; +const short UDPSendPort = 11000; +const short UDPRecvPort = 11001; +const int BUFFER_MAX_SIZE = 4096; + +enum ConnectionStatus +{ + OFFLINE, + ONLINE_MAINMENU, + ONLINE_QUEUEING, + ONLINE_INLOBBY, + ONLINE_INGAME +}; +class SocketClient +{ +private: + HANDLE threadhandle[2]; + int sendDelayMS; + + //2 bools used to verify the activation of the client so threads can't start too early + ConnectionStatus connStatus; + bool setupStatus; + bool connectStatus; + + //iResult is used to check error codes + int iResult; + //wsaData records error messages and errors which winsock might encounter + WSADATA wsaData; + + //Main socket + SOCKET connUDP; + SOCKET connTCP; + + //Addresses used for data transfer + sockaddr_in TCPrecvAddr; + sockaddr_in TCPsendAddr; + //UDPrecvAddr marks the port and IP adress the server is supposed to return data to. + sockaddr_in UDPrecvAddr; + //UDPsendAddr marks which IP and port the client is supposed to send data to. + sockaddr_in UDPsendAddr; + //size of a sockaddr_in. This might as well be a constant, but i'm keeping it in the class for performance reasons. + int addrSize; + + //buffer which is filled when data receive happens. + char* recvBuffer; + //this variable tracks the buffer length. + int recvBufLen; + + //dataBuf is a buffer solely for sending your own user data. It never changes size in order to increase performance. + //char* sendBuffer; + //int sendBufLen; + //PlayerStruct tmpPlayer; + char* dataBuf; + int playerDataSize; +public: + void setPlayerDataSize(int pds){playerDataSize=pds;} + //Constructor + SocketClient(); + + //Initiation for sockets. + bool init(int listenPort); + bool initTCPSocket(int listenPort); + bool initUDPSocket(int listenPort); + //Connects to a server of a user-defined IP. Can only be called after an initXSocket has gone through. + //The 2 remaining variables are init data and size of said data. Currently username. + bool connectToIP(const char* ip, int listenPort, char* initData, int initDataSize); + //sends an undefined data type of (variable#2) size to the server. + bool sendDataUDP(const char*, int); + bool sendDataTCP(const char*, int); + //sends a text string to the server. + bool sendMessage(std::string str); + bool sendServerMessage(std::string str); + //sends user data to the server + bool sendUserData(); + bool sendUserData(char* data, int size); + + //Closes connection, kills off the socket. + bool closeConnection(); + + //Simple ifBoolIsTrue checks + bool isReady() const {return setupStatus;} + bool isConnected() const {return connectStatus;} + void receiveDataWaitOnResponse(); + //Sends data periodically + static void sendDataThreadV(SocketClient* ptr); + //Receive loop. This is event-based and is on its own thread. + static void receiveDataThreadV(SocketClient* ptr); + //Once data is received, it calls on the parseReceivedData function. + void parseReceivedData(); + //void parseReceivedKeyframe(); + //If an event is called from the server, this function will be called. + void parseReceivedEvent(); + void parseReceivedEffect(); + //It is then sent to one of the following functions based on the first byte of the buffer. + + //Servermessage + void parseServermessage(); + //single user data + void parseData(); + //string (character data) + void parseMessage(); + //init data which sets the start position etc of all characters. + void parseLobbyInitData(); + void parseGameInitData(); + void parseRenderData(); + + bool startReceiveThread(); + bool startSendDataThread(); + void setSendDelay(int ms){sendDelayMS=ms;} + + //virtual functions + virtual void receiveGameInitData(char*)=0; + virtual void receiveLobbyInitData(char*, int)=0; + virtual void receivePlayerUpdate(char*, int)=0; + virtual void receiveRenderData(char*, int)=0; + virtual void receiveEffectData(char*, int)=0; + virtual void receiveConnStatus(ConnectionStatus)=0; + virtual void receiveEvent(char*)=0; +}; \ No newline at end of file diff --git a/Network/OysterNetworkServer/Game.cpp b/Network/OysterNetworkServer/Game.cpp new file mode 100644 index 00000000..7948603d --- /dev/null +++ b/Network/OysterNetworkServer/Game.cpp @@ -0,0 +1,113 @@ +#include "Game.h" +Game::Game() +{ + playerCount=0; + started=false; + for (int i=0; i usr, int nrOfPlayers) +{ + /*for (int i=0; isetGame(2); + //init.players[i]=players[i]; + } + return init; +} +void Game::addUser(int uid) +{ + userID[playerCount++]=uid; +} +bool Game::startGame() +{ + started=true; + return started; +} +void Game::update(float dt) +{ + +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/Game.h b/Network/OysterNetworkServer/Game.h new file mode 100644 index 00000000..d162a322 --- /dev/null +++ b/Network/OysterNetworkServer/Game.h @@ -0,0 +1,51 @@ +#pragma once +#ifndef GAME_H +#define GAME_H +#include "User.h" +#include "ServerInclude.h" +const int MUTEX_COUNT =2; +//Mutex #0=playerPos setGet +//Mutex #1= + +//#include "Session.h" + +class Game +{ +private: + bool started; + //ClientToServerUpdateData players[PLAYER_MAX_COUNT]; + User* users[PLAYER_MAX_COUNT]; + int userID[PLAYER_MAX_COUNT]; + bool ready[PLAYER_MAX_COUNT]; + int playerCount; + + //Tracks which ship each user has + int shipID[PLAYER_MAX_COUNT]; + HANDLE mutex[MUTEX_COUNT]; + //::Game::Session *session; + int sessionID; +public: + //Will reset all data + //playerIDs is an array of int which points toward each users connection. + void setReady(int pid, bool rdy){ready[pid]=rdy;} + bool allReady(){for (int i=0; i players, int nrOfPlayers); + GameInitData getInitData(); + bool startGame(); + bool isStarted(){return started;} + Game(); + //Float4x4 getPlayerPos(int id); + //void setPlayerPos(int id, Float4x4 pos); + //bool checkMoveValidity(ClientToServerUpdateData plr); + //ClientToServerUpdateData getPlayerData(int id); + //void setPlayerData(int id, ClientToServerUpdateData ps); + + int getPlayerCount() {return playerCount;} + int getUserID(int i) {return userID[i];} + + void initLUA(char* file); + void update(float dt); + void addUser(int uid); + void removeUser(int uid){playerCount--;} +}; +#endif \ No newline at end of file diff --git a/Network/OysterNetworkServer/Lobby.cpp b/Network/OysterNetworkServer/Lobby.cpp new file mode 100644 index 00000000..ade4b120 --- /dev/null +++ b/Network/OysterNetworkServer/Lobby.cpp @@ -0,0 +1,73 @@ +#include "Lobby.h" + +Lobby::Lobby() +{ + timerStarted=false; + nrUsers=0; + timerMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (timerMutex == NULL) + { + printf("CreateMutex error: %d\n", GetLastError()); + } + for(int i=0; i0) + return timeLeft; + else + return 0; + } + ReleaseMutex(timerMutex); +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/Lobby.h b/Network/OysterNetworkServer/Lobby.h new file mode 100644 index 00000000..a17e771c --- /dev/null +++ b/Network/OysterNetworkServer/Lobby.h @@ -0,0 +1,27 @@ +#include "ServerInclude.h" +#include "User.h" +#ifndef LOBBY_H +#define LOBBY_H +class Lobby +{ +private: + int nrUsers; + int userID[PLAYER_MAX_COUNT]; + ServerTimer countdownTimer; + float countdownLimit; + LobbyUserStruct userData[PLAYER_MAX_COUNT]; + bool timerStarted; + HANDLE timerMutex; +public: + Lobby(); + void addUser(User usr, int i); + int getUserID(int i) const {return userID[i];} + int getNrPlayers() const {return nrUsers;} + void removeUser(); + void updateUserData(LobbyUserStruct); + LobbyInitData getLobbyInitData(); + void startLobbyCountdown(float seconds); + float timeLeft(); + +}; +#endif \ No newline at end of file diff --git a/Network/OysterNetworkServer/ServerDataHandler.cpp b/Network/OysterNetworkServer/ServerDataHandler.cpp new file mode 100644 index 00000000..55c36a02 --- /dev/null +++ b/Network/OysterNetworkServer/ServerDataHandler.cpp @@ -0,0 +1,219 @@ +#include "SocketServer.h" + + + +void SocketServer::parseReceivedData(int threadID/*char* data, int size*/) +{ + bool test=false; + for(unsigned int i=0; isrcAddr); + data->buffer[data->dataSize]='\0'; + usr.setUsername(data->buffer); + users.push_back(usr); + sendData(((int)users.size())-1, "\4connected",10); + std::string asd=users[users.size()-1].getUsername(); + printf("Username:%s, IP:%s\n",users[users.size()-1].getUsername().c_str(), inet_ntoa(users[users.size()-1].getAddr().sin_addr)); +} +void SocketServer::removeUser(int id) +{ + games[users[id].getGame()].removeUser(id); + users.erase(users.begin()+id); +} +void SocketServer::parseServercommand(int pid, int threadID) +{ + connData[threadID].buffer[connData[threadID].dataSize]='\0'; + wprintf(L"User %d sent a server command.\n", pid); + printf("The command is the following:%s.\n", connData[threadID].buffer+1); + std::vector list=splitString(connData[threadID].buffer+1, ' '); + bool validcommand=false; + if(list.size()==0) + { + //Ignore case 1, to avoid vector subscript out of range errors + } + //First variable: Command + else if(!list[0].compare(" ")) + { + //Add rest ignore cases here + } + else if(!list[0].compare("help")) + { + validcommand=true; + } + //else if(!list[0].compare("startgame")) + //{ + //validcommand=true; + //Do more than just sending init data here + //sendInitData(); + //} + else if (!list[0].compare("exit")) + { + validcommand=true; + //User #pid needs to be removed here, and data needs to be sorted accordingly. + } + else if (!list[0].compare("qst")) + { + validcommand=true; + if (users[pid].getState()==ONLINE) + { + sendData(pid, "\4qst",4); + users[pid].setState(ONLINE_QUEUEING); + } + } + else if (!list[0].compare("qed")) + { + validcommand=true; + if (users[pid].getState()==ONLINE_QUEUEING) + { + sendData(pid, "\4qed",4); + users[pid].setState(ONLINE); + } + } + else if (!list[0].compare("rdy")) + { + if (users[pid].getState()==ONLINE_INGAME) + { + games[users[pid].getGame()].setReady(pid, true); + } + } + else if (!list[0].compare("dc")) + { + validcommand=true; + printf("User %s (ID:%d) has disconnected.",users[pid].getUsername().c_str(), pid); + users[pid].setState(OFFLINE); + removeUser(pid); + //Tell games that he might be in here taht he's down + //users.erase(users.begin() + } + else if((!list[0].compare("w")||!list[0].compare("whisper")||!list[0].compare("msg")) && list.size()>2) + { + validcommand=true; + for(unsigned int i=0; i1) + { + users[pid].setUsername(list[1]); + //list[1]="\3Your username has been changed to "+list[1]; + //sendData(pid,list[1].c_str(), list[1].length()); + validcommand=true; + } + } + if(!validcommand) + { + int a=0; + //sendData(pid, "\3Invalid server command.", 24); + //Tell user that the server command was invalid + } +} +void SocketServer::parseData(int pid, int gid, int threadID) +{ + memcpy(&connData[threadID].tmpdata,connData[threadID].buffer+1,CLIENT_PLAYER_DATA_SIZE); + //No old packets + if (users[pid].getLastUpdate()accessPlayer(pid),connData[threadID].tmpdata); + } +} +void SocketServer::parseMessage(int pid, int threadID) +{ + std::string message; + message="\3[Chat] "+users[pid].getUsername()+": "+(connData[threadID].buffer+1); + sendData(-1,message.c_str(), (int)message.length()); +} +void SocketServer::sendInitData(int gid) +{ + GameInitData init=games[gid].getInitData(); + //int test=session->getNumPlayers(); // getNumPlayers is removed + for (int i=0; iaccessPlayer(i).getOrientation(); + } + char* gd=new char[sizeof(init)+1]; + gd[0]=2; + for (int i=0; i +#define DEBUG_NEW new(_NORMAL_BLOCK ,__FILE__, __LINE__) +#else +#define DEBUG_NEW new +#endif + +#include +#include +#include +#include +#include "OysterMath.h" +#include "Session.h" +#include "ServerTimer.h" +using namespace Network; + +const float GAME_UPDATEDELAY=1.0f/120.0f; diff --git a/Network/OysterNetworkServer/ServerMain.cpp b/Network/OysterNetworkServer/ServerMain.cpp new file mode 100644 index 00000000..6c3d7f56 --- /dev/null +++ b/Network/OysterNetworkServer/ServerMain.cpp @@ -0,0 +1,47 @@ +#include +#include "SocketServer.h" +#include "ServerTimer.h" +#include +#include +#include +//#ifdef WINDOWS +#include +#include "ServerInclude.h" +#define GetCurrentDir _getcwd +//#else + //For other OS than windows; can't be found on + //all windows setups so it's commented for now + //#include + //#define GetCurrentDir getcwd + //#endif + +char* getCurDir() +{ + char* cCurrentPath; + cCurrentPath=new char[FILENAME_MAX]; + int test=sizeof(cCurrentPath); + if (!GetCurrentDir(cCurrentPath, FILENAME_MAX)) + { + return "ERROR"; + } + cCurrentPath[FILENAME_MAX - 1] = '\0'; + return cCurrentPath; +} +int main(int argc, char *argv[]) +{ + srand((unsigned int)time(0)); + ::Oyster::Game::MoveAble::setDiscreteTimeSlice( GAME_UPDATEDELAY ); + + SocketServer server; + server.loadMapList("..\\Content\\Maplist.txt"); + while (!server.isReady()); + server.startThreads(); + GameLogic::Object::init("NOT_IMPLEMENTED"); + server.startGameCreateLoop(50); + while(true) + { + server.updateServers(); + } + server.closeConnection(); + return 0; +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/ServerTCPSpecific.cpp b/Network/OysterNetworkServer/ServerTCPSpecific.cpp new file mode 100644 index 00000000..eb6987c9 --- /dev/null +++ b/Network/OysterNetworkServer/ServerTCPSpecific.cpp @@ -0,0 +1,66 @@ +#include "SocketServer.h" +bool SocketServer::initTCPSocket() +{ + //---------------------- + // Create a SOCKET for listening for incoming connection requests. + TCPSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (TCPSocket == INVALID_SOCKET) { + wprintf(L"TCP socket function failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + + iResult = bind(TCPSocket, (SOCKADDR *) & TCPRecvAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"TCP bind function failed with error %d\n", WSAGetLastError()); + iResult = closesocket(TCPSocket); + if (iResult == SOCKET_ERROR) + wprintf(L"TCP closesocket function failed with error %d\n", WSAGetLastError()); + WSACleanup(); + return false; + } + return true; +} +DWORD SocketServer::activateTCPConnectLoop(ThreadArguments* tra) +{ + while (true) + { + (tra->ptr)->receiveConnection(tra->threadID); + } +} +void SocketServer::receiveConnection(int threadID) +{ + User tmp; + //---------------------- + // Listen for incoming connection requests + // on the created socket + if (listen(TCPSocket, SOMAXCONN) == SOCKET_ERROR) + { + wprintf(L"listen function failed with error: %d\n", WSAGetLastError()); + return; + } + + printf("Starting TCP connection loop.\n"); + int a=0; + while(a==0) + { + a=1; + tmp.connection=accept(TCPSocket, (struct sockaddr*)&TCPRecvAddr, &addrSize); + printf("Accepted a TCP connection from IP %s.\n", inet_ntoa(TCPRecvAddr.sin_addr)); + tcpData[threadID].dataSize=recv( + tmp.connection, + tcpData[threadID].buffer, + tcpData[threadID].bufLen, + 0); + connData[threadID].buffer[connData[threadID].dataSize]='\0'; + tmp.setUsername(tcpData[threadID].buffer); + if (tcpData[threadID].dataSize == SOCKET_ERROR) + { + wprintf(L"TCP recv failed with error %d\n", WSAGetLastError()); + } + printf("TCP Thread #%d received connData from %s\n", threadID, inet_ntoa(tcpData[threadID].srcAddr.sin_addr)); + //connData[threadID].buffer[connData[threadID].dataSize]='\0'; + //AddUser(&tcpData[threadID]); + //parseReceivedData(threadID); + } +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/ServerTimer.cpp b/Network/OysterNetworkServer/ServerTimer.cpp new file mode 100644 index 00000000..4dc3d286 --- /dev/null +++ b/Network/OysterNetworkServer/ServerTimer.cpp @@ -0,0 +1,85 @@ +#include "ServerTimer.h" +ServerTimer::ServerTimer() + : + c_SecondsPerCount(0.0), + c_DeltaTime(-1.0), + c_BaseTime(0), + c_PausedTime(0), + c_PrevTime(0), + c_CurrTime(0), + c_Stopped(false) +{ + __int64 countsPerSec; + QueryPerformanceFrequency((LARGE_INTEGER*)&countsPerSec); + c_SecondsPerCount =1.0 / (double)countsPerSec; + + QueryPerformanceCounter((LARGE_INTEGER*)&c_PrevTime); +} + +void ServerTimer::start() +{ + __int64 p_StartTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_StartTime); + if(c_Stopped) + { + c_PausedTime += (p_StartTime-c_StopTime); + c_PrevTime = p_StartTime; + c_StopTime = 0; + c_Stopped = false; + } +} +__int64 ServerTimer::getTime() +{ + __int64 testInt; + return QueryPerformanceCounter((LARGE_INTEGER*)&testInt); + return testInt; +} + +void ServerTimer::stop() +{ + if(!c_Stopped) + { + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_StopTime = p_CurrTime; + c_Stopped = true; + } +} +void ServerTimer::reset() +{ + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_BaseTime = p_CurrTime; + c_PrevTime = p_CurrTime; + c_StopTime = 0; + c_Stopped = false; +} +void ServerTimer::tick() +{ + if (c_Stopped) + { + c_DeltaTime= 0.0; + return; + } + __int64 p_CurrTime; + QueryPerformanceCounter((LARGE_INTEGER*)&p_CurrTime); + c_CurrTime=p_CurrTime; + + c_DeltaTime=(c_CurrTime-c_PrevTime)*c_SecondsPerCount; + c_PrevTime=c_CurrTime; + if(c_DeltaTime<0.0) c_DeltaTime=0.0; +} +float ServerTimer::getGameTime() const +{ + if(c_Stopped) + { + return (float)((c_StopTime-c_BaseTime)*c_SecondsPerCount); + } else + { + return (float)(((c_CurrTime-c_PausedTime)-c_BaseTime)*c_SecondsPerCount); + } +} +float ServerTimer::getDeltaTime() const +{ + return (float)c_DeltaTime; +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/ServerTimer.h b/Network/OysterNetworkServer/ServerTimer.h new file mode 100644 index 00000000..660c1799 --- /dev/null +++ b/Network/OysterNetworkServer/ServerTimer.h @@ -0,0 +1,25 @@ +#include "ServerInclude.h" +#ifndef _GAME_TIMER_H +#define _GAME_TIMER_H +class ServerTimer +{ +private: + double c_SecondsPerCount; + double c_DeltaTime; + __int64 c_BaseTime; + __int64 c_PausedTime; + __int64 c_StopTime; + __int64 c_PrevTime; + __int64 c_CurrTime; + bool c_Stopped; +public: + ServerTimer(); + __int64 getTime(); + void start(); + void stop(); + void reset(); + void tick(); + float getGameTime() const; + float getDeltaTime() const; +}; +#endif \ No newline at end of file diff --git a/Network/OysterNetworkServer/ServerUDPSpecific.cpp b/Network/OysterNetworkServer/ServerUDPSpecific.cpp new file mode 100644 index 00000000..1ffdf624 --- /dev/null +++ b/Network/OysterNetworkServer/ServerUDPSpecific.cpp @@ -0,0 +1,55 @@ +#include "SocketServer.h" +bool SocketServer::initUDPSocket() +{ + //--------------------------------------------- + // Create a socket for sending data + UDPSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (UDPSocket == INVALID_SOCKET) { + wprintf(L"UDP socket failed with error: %ld\n", WSAGetLastError()); + WSACleanup(); + return false; + } + //--------------------------------------------- + // Bind socket to IP + iResult = bind(UDPSocket, (SOCKADDR *) & UDPRecvAddr, addrSize); + if (iResult == SOCKET_ERROR) { + wprintf(L"UDP bind failed with error: %d\n", WSAGetLastError()); + closesocket(UDPSocket); + WSACleanup(); + return false; + } + return true; +} +DWORD SocketServer::activateUDPReceiveLoop(ThreadArguments* tra) +{ + (tra->ptr)->serverUDPReceiveLoopActive=true;//weird crash //PAR + (tra->ptr)->receiveDataUDP(tra->threadID); + return 0; +} +void SocketServer::stopUDPReceiveLoops() +{ + serverUDPReceiveLoopActive=false; + WaitForMultipleObjects(NR_CONNECTTHREADS, udpDataHandle, true, INFINITE); + printf("All UDP data recv threads stopped.\n"); +} +void SocketServer::receiveDataUDP(int threadID) +{ + while(serverUDPReceiveLoopActive) + { + connData[threadID].dataSize=recvfrom( + UDPSocket, + connData[threadID].buffer, + connData[threadID].bufLen, + 0, + (SOCKADDR *)&connData[threadID].srcAddr, + &addrSize); + if (connData[threadID].dataSize == SOCKET_ERROR) + { + wprintf(L"recvfrom failed with error %d\n", WSAGetLastError()); + } + //printf("Thread #%d received data from %s\n", threadID, inet_ntoa(connData[threadID].srcAddr.sin_addr)); + //connData[threadID].buffer[connData[threadID].dataSize]='\0'; + else + parseReceivedData(threadID); + } +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/Servercore.cpp b/Network/OysterNetworkServer/Servercore.cpp new file mode 100644 index 00000000..6dd855fd --- /dev/null +++ b/Network/OysterNetworkServer/Servercore.cpp @@ -0,0 +1,420 @@ +#include "SocketServer.h" +#include +bool SocketServer::loadMapList(char* maploc) +{ + ::std::string workDir; + ::Utility::String::extractDirPath( workDir, maploc, '\\' ); + + //maploc is the filename of the list which contains all maps + //load all map file names into the server, but don't load the maps themselves. + std::ifstream file; + file.open(maploc); + if (!file.is_open()) + return false; + ::std::string str; + while(!file.eof()) + { + ::std::getline( file, str ); + maps.push_back( workDir + str ); + } + + /* + maps.push_back("map1test.map"); + maps.push_back("map2 test.map"); + */ + return true; +} +bool SocketServer::LoadInitData(char* maploc) +{ + std::vector cont; + char* in=new char[100]; + std::ifstream ifs; + ifs.open(maploc); + if(!ifs.is_open()) + { + return false; + } + while(!ifs.eof()) + { + ifs.getline(in, 100); + cont=splitString(in, '='); + if (cont.size()==2) + { + if(!strcmp("nr_players_per_session", cont[0].c_str())) + { + playersPerSessionCount=atoi(cont[1].c_str()); + } + else if(!strcmp("nr_kills_to_win", cont[0].c_str())) + { + killsRequiredPerSession=atoi(cont[1].c_str()); + } + else if(!strcmp("match_type", cont[0].c_str())) + { + //Isn't used + } + } + + } + ifs.close(); +} +SocketServer::~SocketServer() +{ + serverTCPConnectionLoopActive=false; + serverUDPReceiveLoopActive=false; + serverTCPReceiveLoopActive=false; + for (int i=0; iptr)->serverGameCreationLoop(tra->threadID); + return 0; +} +bool SocketServer::serverGameCreationLoop(int delay) +{ // TODO: Mem access Violoation Crash 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ... delay = -858993460 + //Mem access violation in a thread can also be caused by failure from something else instead of it, + //it still breaks at header even if, for example, server->load or lobby.startLobbyCountdown breaks it + //If you get an error here, make sure that isn't the problem. + int count; + while(serverGameCreationActive) + { + if (nrActiveSessions==0) + { + count=0; + for (unsigned int i=0; i=playersPerSessionCount) + { + games.resize(1); + //lobby.resize(games.size()+1); + session =new GameLogic::Session(); + lobby = Lobby(); + timer.resize(1); + timeTillUpdate.resize(1); + timeTillUpdate[0]=GAME_UPDATEDELAY; + updateCount.resize(1); + updateCount[0]=0; + int curID=(int)games.size()-1; + int mapid=rand()%maps.size(); + session->setNrPlayers(playersPerSessionCount); + session->setKillsRequired(killsRequiredPerSession); + session->load(maps[mapid]); + printf("Map nr %d loaded, name %s.\n",mapid, maps[mapid].c_str()); + count=0; + for (unsigned int i=0; countaccessPlayer(i).spawn(); + count++; + } + } + lobbyActive=true; + sendLobbyInitData(curID); + lobby.startLobbyCountdown(LOBBY_WAIT_TIME); + sendRenderData(curID); + //return true; + } + if(lobbyActive) + { + for (int i=0; i<1; i++) + { + float ttimer=lobby.timeLeft(); + if (ttimer==0) + { + printf("Starting game.\n"); + games[i].initGame(users,playersPerSessionCount); + sendInitData(i); + nrActiveSessions++; + lobbyActive=false; + //serverGameCreationActive=false; + } + } + } + } + Sleep(delay); + } + printf("Maximum server count reached, shutting down the sever creation thread.\n"); + return false; +} +SocketServer::SocketServer() +{ + UDPSocket = INVALID_SOCKET; + nrActiveSessions=0; + serverGameCreationActive=false; + serverTCPConnectionLoopActive=false; + serverTCPReceiveLoopActive=false; + serverUDPReceiveLoopActive=false; + killsRequiredPerSession=10; + playersPerSessionCount=1; + LoadInitData("../ServerData.dat"); + //--------------------------------------------- + // Set up the port and IP of the server + //Port starts up as a different one from when UDPSocketected, it changes once the server has exchanged some info with the client + UDPRecvAddr.sin_family = AF_INET; + UDPRecvAddr.sin_port = htons(UDPRecvPort); + UDPRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + sessionEvents=std::vector(0); + sessionEffects=std::vector(0); + TCPRecvAddr.sin_family = AF_INET; + TCPRecvAddr.sin_port = htons(TCPRecvPort); + TCPRecvAddr.sin_addr.s_addr = htonl(INADDR_ANY); + + addrSize=sizeof(sockaddr_in); + for (int i=0; i=users.size()) + { + //User doesn't exist + printf("UDP sendData(%d) sendto failed because the specified user does not exist\n", uid); + } + else + { + iResult = sendto(UDPSocket, data, size, 0, (SOCKADDR *) & users[uid].getAddr(), addrSize); + if (iResult == SOCKET_ERROR) + { + wprintf(L"UDP sendData(%d) sendto failed with error: %d\n", uid, WSAGetLastError()); + closesocket(UDPSocket); + WSACleanup(); + return false; + } + } + } + return true; +} +bool SocketServer::sendKeyFrameData(int size, const char* data) +{ + for (int i=0; i +#include +namespace Benchmark +{ + struct + { + double averageTime, totalTime, minTime, maxTime; unsigned int numSamples; + } timerData[10] = { 0.0f, 0.0f, ::std::numeric_limits::max(), -::std::numeric_limits::max(), 0 }; + + void sampleTime( const ::Utility::WinTimer &timer, unsigned char ref ) + { + double elapsedTime = timer.getElapsedSeconds(); + timerData[ref].totalTime += elapsedTime; + timerData[ref].minTime = ::Utility::Value::min( timerData[ref].minTime, elapsedTime ); + timerData[ref].maxTime = ::Utility::Value::max( timerData[ref].maxTime, elapsedTime ); + ++timerData[ref].numSamples; + timerData[ref].averageTime = timerData[ref].totalTime / (double) timerData[ref].numSamples; + } + + void print( ) + { + ::std::ofstream file; + file.open( "BenchMarkData.txt", ::std::ios_base::app | ::std::ios_base::out ); + + if( file.is_open() ) + { + file << "minTime\t\t: maxTime\t: averageTime\t\ttotalTime\tnumSamples\n"; + for( unsigned char i = 0; i < 1; ++i ) + file << timerData[i].minTime << (timerData[i].minTime == 0.0f ? "\t\t: " : "\t: ") << timerData[i].maxTime << "\t: " << timerData[i].averageTime << "\t\t" << timerData[i].totalTime << '\t' << timerData[i].numSamples <<'\n'; + file << ::std::endl; + file.close(); + ::std::cout << "Benchmark data saved." << ::std::endl; + } + } +} +// END BENCHMARK BLOCK/**/ + +void SocketServer::updateServers() +{ + for(int i=0; iupdate( timer[i].getDeltaTime() ) ) + { + case ::GameLogic::Session::Updated: + // BENCHMARK BLOCK + //processTimer.reset(); + // END BENCHMARK BLOCK + + processSessionPlayerData(i); + processAllSessionEvents(i); + processAllSessionEffects(i); + + // BENCHMARK BLOCK + //Benchmark::sampleTime( processTimer, 0 ); + // END BENCHMARK BLOCK + + DEBUGCTR=0; + updateCount[i]++; + default: + break; + case ::GameLogic::Session::Over: + processAllSessionEvents(i); + nrActiveSessions=0; + if(users.size()==0) + { + printf("Game with id %d done, shutting down the game.\n", 0); + Sleep(10); + + } + break; + } + + // BENCHMARK BLOCK + //if( Benchmark::timerData[0].numSamples % 1000 == 1 ) + // Benchmark::print(); + // END BENCHMARK BLOCK + } + } + if(nrActiveSessions==0) + { + Sleep(50); + } +} +void SocketServer::processSessionPlayerData(int serverID) +{ + sendGameDataStruct.updateCount=updateCount[serverID]; + int offset=1; + for (int i=0; iaccessPlayer(i).getOrientation(); + sendGameDataStruct.hp=session->accessPlayer(i).getHullPoints(); + sendGameDataStruct.shield=session->accessPlayer(i).getShieldPoints(); + sendGameDataStruct.dirVecLen=session->accessPlayer(i).getMovement().length(); + sendGameDataStruct.pid=i; + memcpy(sendGameDataBuffer+offset, &sendGameDataStruct, SERVER_PLAYER_DATA_SIZE); + offset+=SERVER_PLAYER_DATA_SIZE; + } + sendData(-1,sendGameDataBuffer, sendGameDataBufferSize); +} +void SocketServer::processAllSessionEvents(int serverID) +{ + session->fetchEvents(sessionEvents); + for (int i=0; i<(int)sessionEvents.size(); i++) + { + sendEventData(serverID, i); + delete sessionEvents[i]; + } + sessionEvents.resize(0); +} +bool SocketServer::sendGameData(int serverID) +{ + //data[0]=1; + for (int i=0; iGetSize(); + int size1=sizeof(Event::BulletCreated); + int tst=sizeof(Event::Type); + char* ed=new char[size+1+tst]; + ed[0]=6; + sessionEvents[sid]->SaveRawData(ed+(1+tst)); + + Event::Type eTest=Event::getEventType(sessionEvents[sid]); + memcpy(ed+1, &eTest, sizeof(Event::Type)); + + sendData(-1, ed, size+1+tst); + delete ed; +} +void SocketServer::sendRenderData(int gid) +{ + Protocol::RenderData data; + session->writeToRenderResourceData(data); + int size=data.getRequiredBufferSize()+1; + char* sendChar=new char[size]; + data.fillBuffer(sendChar+1); + sendChar[0]=8; + sendData(-1, sendChar, size); + delete sendChar; +} +void SocketServer::processAllSessionEffects(int gid) +{ + session->fetchEffectData(sessionEffects); + + if (sessionEffects.size()>0) + { + int size=(int)sessionEffects.size()*sizeof(Network::EffectData) + 1; + delete sendEffectDataBuffer; + sendEffectDataBuffer=new char[size]; + for (size_t i=0; i0) + p.thrustForward(); + if(update.forward<0) + p.thrustBackward(); + + if(update.straferight>0) + p.strafeRight(); + if(update.straferight<0) + p.strafeLeft(); + + if(update.strafeup>0) + p.climb(); + if(update.strafeup<0) + p.dive(); + + if(update.roll>0) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.roll; + p.rotationProperty.acceleration.roll /= ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + + p.rollLeft(); + p.rotationProperty.acceleration.roll = baseAcceleration; + } + if(update.roll<0) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.roll; + p.rotationProperty.acceleration.roll /= ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + p.rollRight(); + p.rotationProperty.acceleration.roll = baseAcceleration; + } + if(update.roll==0) + { + p.stopRotation(); + } + + if(update.TurnVer!=0.0f) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.pitch; + p.rotationProperty.acceleration.pitch *= -update.TurnVer / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + p.pitchUp( ); + p.disableRotationReduction(); + p.rotationProperty.acceleration.pitch = baseAcceleration; + } + + if(update.TurnHor!=0.0f) + { + ::Oyster::Math::Float baseAcceleration = p.rotationProperty.acceleration.yaw; + p.rotationProperty.acceleration.yaw *= -update.TurnHor / ::Oyster::Game::MoveAble::getDiscreteTimeSlice(); + p.yawLeft( ); + p.disableRotationReduction(); + p.rotationProperty.acceleration.yaw = baseAcceleration; + } + if(update.firePrim) + p.firePrimaryWeapon(); +} + diff --git a/Network/OysterNetworkServer/SocketServer.h b/Network/OysterNetworkServer/SocketServer.h new file mode 100644 index 00000000..28c19058 --- /dev/null +++ b/Network/OysterNetworkServer/SocketServer.h @@ -0,0 +1,126 @@ +#include "Game.h" +#include "Lobby.h" +void ControlPlayer( GameLogic::Player& p,const ClientToServerUpdateData &update); +const int NR_CONNECTTHREADS=1; +const int NR_SIMULTCPCONNECTS=1; +//threads can only take 1 argument +struct ThreadArguments; +struct ConnThreadData +{ + sockaddr_in srcAddr; + + ClientToServerUpdateData tmpdata; + char* buffer; + int bufLen; + int dataSize; +}; +// Link with ws2_32.lib +#pragma comment(lib, "Ws2_32.lib") +const short TCPSendPort = 11111; +const short TCPRecvPort = 11110; +const short UDPSendPort = 11001; +const short UDPRecvPort = 11000; + +class SocketServer +{ +private: + bool serverGameCreationActive; + HANDLE gameCreateHandle; + bool serverTCPConnectionLoopActive; + bool serverUDPReceiveLoopActive; + bool serverTCPReceiveLoopActive; + bool setupStatus; + int iResult; + WSADATA wsaData; + + SOCKET UDPSocket; + SOCKET TCPSocket; + + sockaddr_in TCPRecvAddr; + sockaddr_in UDPRecvAddr; + + int addrSize; + + HANDLE tcpDataHandle[NR_SIMULTCPCONNECTS]; + ConnThreadData tcpData[NR_SIMULTCPCONNECTS]; + + HANDLE udpDataHandle[NR_CONNECTTHREADS]; + ConnThreadData connData[NR_CONNECTTHREADS]; + + int dataSize; + + + char* sendEffectDataBuffer; + char* sendGameDataBuffer; + int sendGameDataBufferSize; + ServerToClientUpdateData sendGameDataStruct; + std::vector users; + std::vector games; + Lobby lobby; + int nrActiveSessions; + std::vector sessionEvents; + std::vector sessionEffects; + GameLogic::Session* session; + std::vector timer; + int DEBUGCTR; + std::vector updateCount; + std::vector timeTillUpdate; + std::vector<::std::string> maps; + std::string text; + int playersPerSessionCount; + int killsRequiredPerSession; + bool lobbyActive; +public: + virtual ~SocketServer(); + //Debug force modify functions + void processAllSessionEvents(int serverID); + void processAllSessionEffects(int gid); + void processSessionPlayerData(int serverID); + //End of debug items + void updateServers(); + SocketServer(); + bool checkConnection(int userID); + bool initUDPSocket(); + bool initTCPSocket(); + //void firstTimeConnect(); + bool loadMapList(char* map); + bool serverGameCreationLoop(int delay); + bool startThreads(); + static DWORD activateUDPReceiveLoop(ThreadArguments* tra); + void stopUDPReceiveLoops(); + //TCP functions + static DWORD activateTCPConnectLoop(ThreadArguments* tra); + void receiveConnection(int threadID); + //End of TCP functions + bool sendData(int uid, const char*, int); + bool sendGameData(int serverID); + bool sendKeyFrameData(int size, const char* data); + void sendInitData(int gid); + void sendRenderData(int gid); + void sendEventData(int gid, int size); + void sendLobbyInitData(int lid); + bool closeConnection(); + void receiveDataUDP(int threadID); + + static DWORD activateServerGameLoop(ThreadArguments* tra); + void startGameCreateLoop(int delay); + void stopGameCreateLoop(); + void parseReceivedData(int threadID/*char*, int*/);//char and int required if i don't want to use the class buffer + void ParseReceivedData(ConnThreadData* data); + + void parseServercommand(int pid, int threadID); + void parseData(int pid, int gid, int threadID); + void parseMessage(int pid, int threadID); + + void addUser(int threadID); + void AddUser(ConnThreadData* data); + void removeUser(int id); + + bool isReady() const {return setupStatus;} + bool LoadInitData(char* maploc); +}; +struct ThreadArguments +{ + SocketServer* ptr; + int threadID; +}; \ No newline at end of file diff --git a/Network/OysterNetworkServer/User.cpp b/Network/OysterNetworkServer/User.cpp new file mode 100644 index 00000000..5dcbdf8d --- /dev/null +++ b/Network/OysterNetworkServer/User.cpp @@ -0,0 +1,50 @@ +#include "User.h" +User::User(int i, sockaddr_in add, std::string usr) +{ + addr=add; + username=usr; + curGame=-1; + connection=NULL; + state=ONLINE; + lastUpdate=-1; + updMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (updMutex == NULL) + { + printf("CreateMutex error: %d\n", GetLastError()); + } +} +User::User() +{ + username=""; + curGame=-1; + connection=NULL; + state=ONLINE; + lastUpdate=-1; + updMutex = CreateMutex( + NULL, // default security attributes + FALSE, // initially not owned + NULL); // unnamed mutex + + if (updMutex == NULL) + { + printf("CreateMutex error: %d\n", GetLastError()); + } + lastUpdateData.pid=-1; +} +void User::setLastUpdateData(Network::ClientToServerUpdateData data) +{ + WaitForSingleObject(updMutex, INFINITE); + lastUpdateData=data; + ReleaseMutex(updMutex); +} +Network::ClientToServerUpdateData User::getLastUpdateData() +{ + WaitForSingleObject(updMutex, INFINITE); + Network::ClientToServerUpdateData data=lastUpdateData; + ReleaseMutex(updMutex); + return data; +} \ No newline at end of file diff --git a/Network/OysterNetworkServer/User.h b/Network/OysterNetworkServer/User.h new file mode 100644 index 00000000..1a68b950 --- /dev/null +++ b/Network/OysterNetworkServer/User.h @@ -0,0 +1,42 @@ +#include "ServerInclude.h" +#ifndef USER_H +#define USER_H +enum UserState +{ + OFFLINE, + OFFLINE_INGAME, + ONLINE, + ONLINE_QUEUEING, + ONLINE_INLOBBY, + ONLINE_INGAME +}; +class User +{ +private: + std::string username; + int curGame; + sockaddr_in addr; + UserState state; + long lastUpdate; + HANDLE updMutex; + Network::ClientToServerUpdateData lastUpdateData; +public: + void setLastUpdateData(Network::ClientToServerUpdateData data); + Network::ClientToServerUpdateData getLastUpdateData(); + void setLastUpdate(long upd){lastUpdate=upd;} + long getLastUpdate() {return lastUpdate;} + HANDLE threadHandle; + SOCKET connection; + User(); + User(int id, sockaddr_in addr, std::string usr="Unknown"); + //SOCKET getTCPSocket() const {return connection;} + sockaddr_in getAddr() const {return addr;} + std::string getUsername() const {return username;} + void setUsername(std::string usr){username=usr;} + void setState(UserState st){state=st;} + UserState getState(){return state;} + void setGame(int gid){curGame=gid;} + bool isIngame() {return state==ONLINE_INGAME;} + int getGame(){return curGame;} +}; +#endif \ No newline at end of file diff --git a/OysterGraphics/Core/Buffer.cpp b/OysterGraphics/Core/Buffer.cpp new file mode 100644 index 00000000..50759848 --- /dev/null +++ b/OysterGraphics/Core/Buffer.cpp @@ -0,0 +1,202 @@ +#include "Buffer.h" +#include "Core.h" +using namespace Oyster; + +Buffer::Buffer() +{ + mBuffer = NULL; +} + +Buffer::~Buffer() +{ + SAFE_RELEASE(mBuffer); +} + +HRESULT Buffer::Apply(UINT32 misc) const +{ + HRESULT hr = S_OK; + + switch(mType) + { + case VERTEX_BUFFER: + { + UINT32 vertexSize = mElementSize; + UINT32 offset = 0; + Oyster::Core::DeviceContext->IASetVertexBuffers(misc, 1, &mBuffer, &vertexSize, &offset ); + } + break; + case INDEX_BUFFER: + { + Oyster::Core::DeviceContext->IASetIndexBuffer(mBuffer, DXGI_FORMAT_R32_UINT, 0); + } + break; + case CONSTANT_BUFFER_VS: + { + Oyster::Core::DeviceContext->VSSetConstantBuffers(misc, 1, &mBuffer); + } + break; + case CONSTANT_BUFFER_GS: + { + Oyster::Core::DeviceContext->GSSetConstantBuffers(misc, 1, &mBuffer); + } + break; + case CONSTANT_BUFFER_PS: + { + Oyster::Core::DeviceContext->PSSetConstantBuffers(misc, 1, &mBuffer); + } + break; + case CONSTANT_BUFFER_CS: + { + Oyster::Core::DeviceContext->CSSetConstantBuffers(misc,1,&mBuffer); + } + break; + default: + hr = E_FAIL; + break; + }; + + return hr; +} + +HRESULT Buffer::Init(const BUFFER_INIT_DESC& initDesc) +{ + D3D11_BUFFER_DESC bufferDesc; + + mType = initDesc.Type; + switch(mType) + { + case VERTEX_BUFFER: + { + bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + + if(initDesc.Usage == BUFFER_STREAM_OUT_TARGET) + bufferDesc.BindFlags |= D3D11_BIND_STREAM_OUTPUT; + } + break; + case INDEX_BUFFER: + { + bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + } + break; + case STRUCTURED_BUFFER: + { + bufferDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + } + break; + case CONSTANT_BUFFER_CS: + case CONSTANT_BUFFER_VS: + case CONSTANT_BUFFER_GS: + case CONSTANT_BUFFER_PS: + { + bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + } + break; + default: + return E_FAIL; + break; + }; + + mUsage = initDesc.Usage; + mElementSize = initDesc.ElementSize; + mElementCount = initDesc.NumElements; + + bufferDesc.CPUAccessFlags = 0; + bufferDesc.Usage = D3D11_USAGE_DEFAULT; + + if(mUsage == BUFFER_CPU_READ) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_READ; + } + else if(mUsage == BUFFER_CPU_WRITE) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + } + else if(mUsage == BUFFER_CPU_WRITE_DISCARD) + { + bufferDesc.Usage = D3D11_USAGE_DYNAMIC; + bufferDesc.CPUAccessFlags |= D3D11_CPU_ACCESS_WRITE; + } + + //Desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + bufferDesc.MiscFlags = 0; + bufferDesc.ByteWidth = initDesc.NumElements * initDesc.ElementSize; + bufferDesc.StructureByteStride=0; + if(mType== STRUCTURED_BUFFER) + { + bufferDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bufferDesc.StructureByteStride=initDesc.ElementSize; + } + //set at least 16 bytes + if(bufferDesc.ByteWidth < 16) + bufferDesc.ByteWidth = 16; + + HRESULT hr = S_OK; + if(initDesc.InitData) + { + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = initDesc.InitData; + data.SysMemPitch=0; + data.SysMemSlicePitch = 0; + hr = Oyster::Core::Device->CreateBuffer(&bufferDesc, &data, &mBuffer); + } + else + { + hr = Oyster::Core::Device->CreateBuffer(&bufferDesc, NULL, &mBuffer); + } + + if(FAILED(hr)) + { + MessageBox(NULL, "Unable to create buffer.", "Slenda Error", MB_ICONERROR | MB_OK); + } + + return hr; +} + +void* Buffer::Map() +{ + void* ret = NULL; + if(mUsage == BUFFER_CPU_WRITE || mUsage == BUFFER_CPU_READ || mUsage == BUFFER_CPU_WRITE_DISCARD) + { + D3D11_MAPPED_SUBRESOURCE MappedResource; + UINT32 mapType = 0; + + if(mUsage == BUFFER_CPU_READ) mapType = D3D11_MAP_READ; + else if(mUsage == BUFFER_CPU_WRITE) mapType = D3D11_MAP_WRITE; + else if(mUsage == BUFFER_CPU_WRITE_DISCARD) mapType = D3D11_MAP_WRITE_DISCARD; + + HRESULT hr = S_OK; + if(FAILED(hr = Oyster::Core::DeviceContext->Map( + mBuffer, + 0, + (D3D11_MAP)mapType, + 0, + &MappedResource))) + { + ret = NULL; + } + else + { + ret = MappedResource.pData; + } + } + + return ret; + +} + +void Buffer::Unmap() +{ + Oyster::Core::DeviceContext->Unmap( mBuffer, 0 ); +} + +Buffer::operator ID3D11Buffer *() +{ + return this->mBuffer; +} + +Buffer::operator const ID3D11Buffer *() const +{ + return this->mBuffer; +} \ No newline at end of file diff --git a/OysterGraphics/Core/Buffer.h b/OysterGraphics/Core/Buffer.h new file mode 100644 index 00000000..712c7ac4 --- /dev/null +++ b/OysterGraphics/Core/Buffer.h @@ -0,0 +1,76 @@ +#pragma once +#ifndef CoreBuffer +#define CoreBuffer + +#include "Core.h" + +namespace Oyster +{ + class Buffer + { + public: + enum BUFFER_TYPE + { + VERTEX_BUFFER, + INDEX_BUFFER, + CONSTANT_BUFFER_VS, + CONSTANT_BUFFER_GS, + CONSTANT_BUFFER_PS, + CONSTANT_BUFFER_CS, + STRUCTURED_BUFFER, + BUFFER_TYPE_COUNT + }; + + enum BUFFER_USAGE + { + BUFFER_DEFAULT, + BUFFER_STREAM_OUT_TARGET, + BUFFER_CPU_WRITE, + BUFFER_CPU_WRITE_DISCARD, + BUFFER_CPU_READ, + BUFFER_USAGE_COUNT + }; + + struct BUFFER_INIT_DESC + { + BUFFER_TYPE Type; + UINT32 NumElements; + UINT32 ElementSize; + BUFFER_USAGE Usage; + void* InitData; + + BUFFER_INIT_DESC() + { + InitData = NULL; + Usage = BUFFER_DEFAULT; + } + }; + protected: + ID3D11Buffer* mBuffer; + BUFFER_TYPE mType; + BUFFER_USAGE mUsage; + + UINT32 mElementSize; + UINT32 mElementCount; + public: + Buffer(); + virtual ~Buffer(); + + HRESULT Init(const BUFFER_INIT_DESC& initDesc); + + void* Map(); + void Unmap(); + + operator ID3D11Buffer*(); + operator const ID3D11Buffer*() const; + + HRESULT Apply(UINT32 misc = 0) const; + + ID3D11Buffer* GetBufferPointer(); + UINT32 GetVertexSize(); + UINT32 GetElementCount(); + }; + +} + +#endif \ No newline at end of file diff --git a/OysterGraphics/Core/Core.cpp b/OysterGraphics/Core/Core.cpp new file mode 100644 index 00000000..feb7a65c --- /dev/null +++ b/OysterGraphics/Core/Core.cpp @@ -0,0 +1,164 @@ +#include "Core.h" +#include "..\Window\Window.h" + +using namespace Oyster; +using std::string; + +//GPU +ID3D11Device *Core::Device = NULL; + +//API +ID3D11DeviceContext *Core::DeviceContext = NULL; + +//SwapChain +IDXGISwapChain* Core::SwapChain = NULL; + +std::stringstream Log; + +inline std::stringstream* AccesLog(){return &Log;} + +bool Core::Init(bool SingleThreaded, bool Reference,bool ForceDX11) +{ + UINT createDeviceFlags = 0; + + if( SingleThreaded ) + createDeviceFlags = ::D3D11_CREATE_DEVICE_SINGLETHREADED; + + ::D3D_DRIVER_TYPE driverType = ::D3D_DRIVER_TYPE_HARDWARE; + + if(Reference) + driverType = D3D_DRIVER_TYPE_REFERENCE; + + /*#if defined(DEBUG) || defined(_DEBUG) + Log << "DirectX running in debug mode.\n"; + createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + #endif*/ + + + D3D_FEATURE_LEVEL featureLevelsToTry[] = + { + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0 + }; + D3D_FEATURE_LEVEL initiatedFeatureLevel; + + if( FAILED( ::D3D11CreateDevice( NULL, // default adapter + driverType, + NULL, // no software device + createDeviceFlags, + featureLevelsToTry, 3, // default feature level array. DX11 support assumed + D3D11_SDK_VERSION, + &Device, // device + &initiatedFeatureLevel, + &DeviceContext ) ) ) // context + { // if failed + if( DeviceContext ) { DeviceContext->Release(); DeviceContext = NULL; } // safe cleanup + if( Device ) { Device->Release(); Device = NULL; } // safe cleanup + } + + if( driverType == ::D3D_DRIVER_TYPE_HARDWARE ) + Log << "D3D_DRIVER_TYPE_HARDWARE support discovered.\n"; + else + Log << "D3D_DRIVER_TYPE_REFERENCE support discovered.\n"; + + if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_11_0 ) + { + Log << "DirectX Featurelevel 11.0 supported.\n"; + } + else + { + if(ForceDX11) + return false; + if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_10_1 ) + { + Log << "DirectX Featurelevel 10.1 supported.\n"; + } + else + { + if( initiatedFeatureLevel == ::D3D_FEATURE_LEVEL_10_0 ) + { + Log << "DirectX Featurelevel 10.0 supported.\n"; + } + } + } + if(Device) + return true; + + return false; +} + +bool Core::CreateSwapChain(HWND Window, int NrofBuffers,bool MSAA_Quality,bool Fullscreen) +{ + //generate static Swapchain Desc + DXGI_SWAP_CHAIN_DESC desc; + desc.OutputWindow=Window; + desc.BufferCount=NrofBuffers; + desc.Windowed=!Fullscreen; + desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_UNORDERED_ACCESS; + desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + desc.Flags=0; + desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; + desc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED; + desc.BufferDesc.RefreshRate.Denominator=1; + desc.BufferDesc.RefreshRate.Numerator=60; + desc.BufferDesc.Height = Window::Size.bottom; + desc.BufferDesc.Width = Window::Size.left; + + //Check and Set multiSampling + if(MSAA_Quality) + { + if(FAILED(Device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&desc.SampleDesc.Quality))) + { + Log<< "Failed to check multisample quality levels (MSAAQuality).\n"; + return false; + } + desc.SampleDesc.Count=4; + --desc.SampleDesc.Quality; + Log << "Supported multisample quality levels (MSAAQuality): " << desc.SampleDesc.Quality+1 << "x\n"; + } + else + { + desc.SampleDesc.Count=1; + desc.SampleDesc.Quality=0; + } + + //Get Device Factory + ::IDXGIDevice *dxgiDevice = NULL; + if( FAILED( Device->QueryInterface( __uuidof( IDXGIDevice ), (void**)&dxgiDevice ) ) ) + { + Log << "Failed to Query for the GPU's dxgiDevice.\nFailed to create swapChain for the GPU.\n"; + return false; + } + + ::IDXGIAdapter *dxgiAdapter = NULL; + if( FAILED( dxgiDevice->GetParent( __uuidof( IDXGIAdapter ), (void**)&dxgiAdapter ) ) ) + { + dxgiDevice->Release(); + Log << "Failed to get GPU's parent dxgiAdapter.\nFailed to create swapChain for the GPU.\n"; + return false; + } + dxgiDevice->Release(); + + ::IDXGIFactory *dxgiFactory = NULL; + if( FAILED( dxgiAdapter->GetParent( __uuidof( IDXGIFactory ), (void**)&dxgiFactory ) ) ) + { + dxgiAdapter->Release(); + Log << "Failed to get GPU's parent dxgiFactory.\nFailed to create swapChain for the GPU.\n"; + return false; + } + dxgiAdapter->Release(); + + //Create SwapChain + if( FAILED( dxgiFactory->CreateSwapChain( Device, &desc, &SwapChain ) ) ) + { + dxgiFactory->Release(); + Log << "Failed to create swapChain for the GPU.\n"; + return false; + } + + dxgiFactory->Release(); + + return true; +} \ No newline at end of file diff --git a/OysterGraphics/Core/Core.h b/OysterGraphics/Core/Core.h new file mode 100644 index 00000000..7cca37fb --- /dev/null +++ b/OysterGraphics/Core/Core.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef Core_h +#define Core_h + + +#include "CoreIncludes.h" +#include +namespace Oyster +{ + class Core + { + public: + + static ID3D11Device* Device; + + static ID3D11DeviceContext* DeviceContext; + + static IDXGISwapChain* SwapChain; + + static std::stringstream* AccesLog(); + + static bool Init(bool SingleThreaded,bool Reference,bool ForceDX11); + + static bool CreateSwapChain(HWND Window, int NrofBuffers,bool MSAA_Quality,bool Fullscreen); + }; +} + + +#endif \ No newline at end of file diff --git a/OysterGraphics/Core/CoreIncludes.h b/OysterGraphics/Core/CoreIncludes.h new file mode 100644 index 00000000..68a0c683 --- /dev/null +++ b/OysterGraphics/Core/CoreIncludes.h @@ -0,0 +1,40 @@ +#pragma once +#ifndef CORE_INCLUDE +#define CORE_INCLUDE + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. +// http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define SAFE_RELEASE(x) if( x ) { (x)->Release(); (x) = NULL; } +#define SAFE_DELETE(x) if( x ) { delete(x); (x) = NULL; } +#define SAFE_DELETE_ARRAY(x) if( x ) { delete[](x); (x) = NULL; } +#define PI (3.14159265358979323846f) + +#pragma comment(lib, "d3d11.lib") +#pragma comment(lib, "d3dcompiler.lib") +#pragma comment (lib,"dxerr.lib") + +#ifdef _DEBUG +#pragma comment(lib, "d3dx11d.lib") +#pragma comment(lib, "Effects11D.lib") +#pragma comment(lib, "d3dx10d.lib") +#else +#pragma comment(lib, "d3dx11.lib") +#pragma comment(lib, "Effects11.lib") +#pragma comment(lib, "d3dx10.lib") +#endif + + +#endif \ No newline at end of file diff --git a/OysterGraphics/Engine.cpp b/OysterGraphics/Engine.cpp new file mode 100644 index 00000000..4dd2aad0 --- /dev/null +++ b/OysterGraphics/Engine.cpp @@ -0,0 +1,539 @@ +#include "Engine.h" + +bool CreateDepthStencil(bool MSAA_Quality); +bool CreateRenderTarget(); +void SetViewPort(); + +class oysterPrivates +{ +public: + bool instance,swapChained; + ID3D11DepthStencilView* depth; + ID3D11RenderTargetView *rtv; + ID3D11UnorderedAccessView *uav; + ID3D11ShaderResourceView* depthTexture; + DXGI_SAMPLE_DESC sampleDesc; + D3D11_VIEWPORT viewPort; + oysterPrivates():instance(false),swapChained(false),depth(NULL),rtv(NULL), depthTexture(NULL){}; + class State + { + public: + int NrOfSamples; + int SampleSpread; + int NrOfPointlights; + }States; + +}instance; + +Oyster::Engine::Engine() +{ +} + +Oyster::Engine::~Engine() +{ +} + +//Init +bool Oyster::Engine::Init::IsInstanced() +{ + return instance.instance; +} + +bool Oyster::Engine::Init::Instance(bool SingleThreaded,bool Reference,bool ForceDX11) +{ + if(!instance.instance) + if(Oyster::Core::Init(SingleThreaded,Reference,ForceDX11)) + instance.instance=true; + + return instance.instance; +} + +bool Oyster::Engine::Init::HasSwapChain() +{ + return instance.swapChained; +} + +bool Oyster::Engine::Init::CreateSwapChain(HWND Window,int NrofBuffers,bool MSAA_Quality,bool Fullscreen) +{ + if(Window==0) + { + if(Oyster::Window::Handle==0) + return false; + else + Window = Oyster::Window::Handle; + } + if(!instance.swapChained) + { + if(Oyster::Core::CreateSwapChain(Window,NrofBuffers,MSAA_Quality,Fullscreen)) + instance.swapChained=true; + } + + return instance.swapChained; +} + +bool Oyster::Engine::Init::InitializeWindow(const LPCSTR appName, const LPCSTR className,const HINSTANCE &hInstance, const int &nCmdShow, WNDPROC wProc, bool handleLoop ) +{ + return Oyster::Window::init(appName,className,hInstance,nCmdShow,wProc,handleLoop); +} + +bool Oyster::Engine::Init::FullInit(const Setup& setup) +{ + if(!Oyster::Engine::Init::Instance(setup.Common.SingleThreaded,setup.Common.Reference,setup.Common.ForceDX11)) + return false; + if(setup.Window.InitWindow) + if(!Oyster::Engine::Init::InitializeWindow(setup.Window.appname,setup.Window.classname,setup.Window.hinstance,setup.Window.nCmdShow,setup.Window.wProc, true)) + return false; + if(!Oyster::Engine::Init::CreateSwapChain(NULL,setup.Common.NrOfBuffers,setup.Common.MSAA_Quality,setup.Common.Fullscreen)) + return false; + if(!Oyster::Shader::InitShaders()) + return false; + if(setup.Common.GenerateDepthStencil) + if(!CreateDepthStencil(setup.Common.MSAA_Quality)) + return false; + if(!CreateRenderTarget()) + return false; + if(!Oyster::Render::Textbox::Init()) + return false; + SetViewPort(); + if(setup.Common.BindDefault) + Oyster::Engine::PrepareForRendering::BindRenderTargets(&instance.rtv,1,instance.depth); + + instance.States.NrOfSamples = 14; + instance.States.SampleSpread = 4; + instance.States.NrOfPointlights = 1024; + + Oyster::Resources::Buffers::Init(); + Oyster::Resources::ShaderEffects::Init(); + Oyster::Resources::PipeLineResourses::Init(); + return true; + +} + +Oyster::Buffer* Oyster::Engine::Init::Buffers::CreateBuffer(const Oyster::Buffer::BUFFER_INIT_DESC desc) +{ + Oyster::Buffer *buffy = new Oyster::Buffer(); + buffy->Init(desc); + return buffy; +} + + +//PrepareForRendering +void Oyster::Engine::PrepareForRendering::BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets,ID3D11DepthStencilView* depth) +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(NrOfTargets,RenderTargets,depth); +} + +void Oyster::Engine::PrepareForRendering::BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets) +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(NrOfTargets,RenderTargets,instance.depth); +} + +void Oyster::Engine::PrepareForRendering::BindBackBufferAsUAV() +{ + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,1,&instance.uav,0); +} + +void Oyster::Engine::PrepareForRendering::BindUAV(ID3D11UnorderedAccessView** uav, int NrOfUavs) +{ + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,NrOfUavs,uav,0); +} + +void Oyster::Engine::PrepareForRendering::ClearBackBuffer(Math::Float4 color) +{ + Oyster::Core::DeviceContext->ClearRenderTargetView(instance.rtv,(float*)color); + Oyster::Core::DeviceContext->ClearDepthStencilView(instance.depth,1,1,0); +} + +void Oyster::Engine::PrepareForRendering::BindBackBuffer(ID3D11DepthStencilView* depth) +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(1,&instance.rtv,depth); +} + +void Oyster::Engine::PrepareForRendering::BindBackBuffer() +{ + Oyster::Core::DeviceContext->OMSetRenderTargets(1,&instance.rtv,instance.depth); +} + +void Oyster::Engine::PrepareForRendering::Begin2DRender() +{ + Oyster::Resources::Buffers::V2DSprites.Apply(); + Oyster::Resources::Buffers::CBufferGs.Apply(); + Shader::SetShaderEffect(Oyster::Resources::ShaderEffects::BasicSprite); +} + +void Oyster::Engine::PrepareForRendering::Begin2DTextRender() +{ + Oyster::Render::Textbox::TextBuffer.Apply(); + Oyster::Resources::Buffers::CBufferGs.Apply(); + Oyster::Shader::SetShaderEffect(Oyster::Resources::ShaderEffects::Text2DEffect); +} + + +//Render +void Oyster::Engine::Render::PresentScene() +{ + Core::SwapChain->Present(0,0); +} + +void Oyster::Engine::Render::Geometry(const Oyster::Render::Model* models,int count,Oyster::Buffer* cBufferEveryObject, int slot) +{ + if(cBufferEveryObject) + cBufferEveryObject->Apply(slot); + for(int i=0;iMap(); + memcpy(data,&(models[i].World->getTranspose()),64); + cBufferEveryObject->Unmap(); + } + Oyster::Core::DeviceContext->PSSetShaderResources(0,models[i].info->Material.size(),&(models[i].info->Material[0])); + + models[i].info->Vertices.Apply(); + if(models[i].info->Indexed) + { + models[i].info->Indecies.Apply(); + Oyster::Core::DeviceContext->DrawIndexed(models[i].info->VertexCount,0,0); + } + else + Oyster::Core::DeviceContext->Draw(models[i].info->VertexCount,0); + } + } +} + +void Oyster::Engine::Render::Text(std::string text, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos) +{ + Pos.x -= Oyster::Window::Size.left/2; + Pos.x += size.x; + + Pos.y -= Oyster::Window::Size.bottom/2; + Pos.y += size.y; + + Matrix m; + Math::identityMatrix(m); + float width = (1.0f/(Window::Size.left/2.0f)); + float height = (1.0f/(Window::Size.bottom/2.0f)); + m.m41=Pos.x * width; + m.m42=-Pos.y * height; + m.m43=Pos.z; + m.m11=width*size.x; + m.m22=height*size.y; + void* dest = Resources::Buffers::CBufferGs.Map(); + memcpy(dest,&m.getTranspose(),64); + Resources::Buffers::CBufferGs.Unmap(); + Oyster::Render::Textbox::Update(text, size.x); + Oyster::Engine::PrepareForRendering::Begin2DTextRender(); + Oyster::Core::DeviceContext->PSSetShaderResources(0,1,&(Oyster::Render::Textbox::Texture)); + //Should be able to be outside of the for loop. Keeping it here for now though. + Oyster::Core::DeviceContext->Draw(Oyster::Render::Textbox::NumLetters, 0); +} + +void Oyster::Engine::Render::ScreenQuad(ID3D11ShaderResourceView* srv, float ZPos) +{ + + Oyster::Core::DeviceContext->PSSetShaderResources(0,1,&srv); + + Matrix m; + Math::identityMatrix(m); + m.m43=ZPos; + + void* dest = Resources::Buffers::CBufferGs.Map(); + memcpy(dest,&m.getTranspose(),64); + Resources::Buffers::CBufferGs.Unmap(); + + Oyster::Core::DeviceContext->Draw(1,0); +} + +void Oyster::Engine::Render::Sprite(ID3D11ShaderResourceView* srv, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos) +{ + + Oyster::Core::DeviceContext->PSSetShaderResources(0,1,&srv); + + Pos.x -= Oyster::Window::Size.left/2; + Pos.x += size.x/2; + + Pos.y -= Oyster::Window::Size.bottom/2; + Pos.y += size.y/2; + + Matrix m; + Math::identityMatrix(m); + float width = (1.0f/(Window::Size.left/2.0f)); + float height = (1.0f/(Window::Size.bottom/2.0f)); + m.m41=Pos.x * width; + m.m42=-Pos.y * height; + m.m43=Pos.z; + m.m11=width*size.x/2; + m.m22=height*size.y/2; + + void* dest = Resources::Buffers::CBufferGs.Map(); + memcpy(dest,&m.getTranspose(),64); + Resources::Buffers::CBufferGs.Unmap(); + + Oyster::Core::DeviceContext->Draw(1,0); +} + +//Misc +bool CreateDepthStencil(bool MSAA_Quality) +{ + + D3D11_TEXTURE2D_DESC desc; + desc.MipLevels=1; + desc.ArraySize=1; + desc.Format = DXGI_FORMAT_D32_FLOAT; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; + desc.CPUAccessFlags=0; + desc.MiscFlags=0; + desc.Height = Oyster::Window::Size.bottom; + desc.Width = Oyster::Window::Size.left; + + + //Check and Set multiSampling + if(MSAA_Quality) + { + if(FAILED(Oyster::Core::Device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&desc.SampleDesc.Quality))) + { + //Log<< "Failed to check multisample quality levels (MSAAQuality).\n"; + return false; + } + desc.SampleDesc.Count=4; + --desc.SampleDesc.Quality; + //Log << "Supported multisample quality levels (MSAAQuality): " << desc.SampleDesc.Quality+1 << "x\n"; + } + else + { + desc.SampleDesc.Count=1; + desc.SampleDesc.Quality=0; + } + + ID3D11Texture2D* depthstencil; + + if(FAILED(Oyster::Core::Device->CreateTexture2D(&desc,0,&depthstencil))) + return false; + if(FAILED(Oyster::Core::Device->CreateDepthStencilView(depthstencil,0,&instance.depth))) + { + depthstencil->Release(); + return false; + } + depthstencil->Release(); + + + + return true; +} + +bool CreateRenderTarget() +{ + D3D11_UNORDERED_ACCESS_VIEW_DESC descView; + ZeroMemory( &descView, sizeof(descView) ); + descView.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; + descView.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + descView.Texture2D.MipSlice=0; + + ID3D11Texture2D* backBuffer; + if(FAILED(Oyster::Core::SwapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),reinterpret_cast(&backBuffer)))) + return false; + if(FAILED(Oyster::Core::Device->CreateRenderTargetView(backBuffer,0,&instance.rtv))) + { + backBuffer->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateUnorderedAccessView(backBuffer,0,&instance.uav))) + { + backBuffer->Release(); + return false; + } + + backBuffer->Release(); + + return true; +} + +void SetViewPort() +{ + instance.viewPort.TopLeftX = 0.0f; + instance.viewPort.TopLeftY = 0.0f; + instance.viewPort.Width = (float)Oyster::Window::Size.left; + instance.viewPort.Height = (float)Oyster::Window::Size.bottom; + instance.viewPort.MinDepth = 0.0f; + instance.viewPort.MaxDepth = 1.0f; + + Oyster::Core::DeviceContext->RSSetViewports(1,&instance.viewPort); +} + +void Blur(int target) +{ + //TODO: proper size calculation + + //bind input + Oyster::Core::DeviceContext->CSSetShaderResources(0,1,&Oyster::Resources::PipeLineResourses::LightOut[target]); + Oyster::Engine::PrepareForRendering::BindUAV(&Oyster::Resources::PipeLineResourses::TempUav,1); + + //dispatch blurr horizontal + Oyster::Shader::Set::SetCompute(Oyster::Shader::Get::GetCompute("BlurHorizontal")); + Oyster::Core::DeviceContext->Dispatch(7,Oyster::Window::Size.bottom,1); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources(0,16,&Oyster::Resources::PipeLineResourses::SrvNulls[0]); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,8,&Oyster::Resources::PipeLineResourses::uavNULL[0],0); + + //bind input + Oyster::Core::DeviceContext->CSSetShaderResources(0,1,&Oyster::Resources::PipeLineResourses::TempSrv); + Oyster::Engine::PrepareForRendering::BindUAV(&Oyster::Resources::PipeLineResourses::LightTarget[target],1); + + //dispatch blurr vertical + Oyster::Shader::Set::SetCompute(Oyster::Shader::Get::GetCompute("BlurVertical")); + Oyster::Core::DeviceContext->Dispatch(Oyster::Window::Size.left,5,1); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources(0,16,&Oyster::Resources::PipeLineResourses::SrvNulls[0]); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews(0,8,&Oyster::Resources::PipeLineResourses::uavNULL[0],0); +} + + +//Pipeline Render +void Oyster::Engine::Pipeline::Deffered_Lightning::NewFrame(const Float4& col, const Matrix& View, const Matrix& Projection) +{ + //diffuse + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[0], col); + + //Specular + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[1], col); + + //Glow + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[2], col); + + //Pos + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[3], col); + + //Normal + Oyster::Core::DeviceContext->ClearRenderTargetView( Oyster::Resources::PipeLineResourses::GeometryTarget[4], col); + + Oyster::Engine::PrepareForRendering::ClearBackBuffer(col); + + //Upload Camera to Resources + + Matrix P = Oyster::Math::Float4x4(Projection); + Matrix V = Oyster::Math::Float4x4(View); + Matrix VP = V*P; + + Oyster::Resources::PipeLineResourses::LightData.projectionMatrix = P.getTranspose(); + Oyster::Resources::PipeLineResourses::LightData.viewMatrix = V; + + Oyster::Collision::Frustrum( VP ).split(Oyster::Resources::PipeLineResourses::SubFrustrums, Oyster::Resources::PipeLineResourses::FrustrumDimensions.x, Oyster::Resources::PipeLineResourses::FrustrumDimensions.y, Oyster::Resources::PipeLineResourses::FrustrumDimensions.z ); + + void* dest = Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[0]->Map(); + memcpy(dest,&VP.getTranspose(),64); + Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[0]->Unmap(); + + dest= Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[1]->Map(); + memcpy(dest,&V.getTranspose(),64); + Oyster::Resources::ShaderEffects::ModelEffect.CBuffers.Vertex[1]->Unmap(); + + dest = Oyster::Resources::PipeLineResourses::Resources[0]->Map(); + unsigned int bytes=0; + for(int i=0;iUnmap(); + + dest = Oyster::Resources::Buffers::CBufferPipelineCs.Map(); + memcpy(dest, &Oyster::Resources::PipeLineResourses::LightData, sizeof( Oyster::Resources::BufferDefinitions::LightStructureBuffer ) ); + Oyster::Resources::Buffers::CBufferPipelineCs.Unmap(); + +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::BeginRenderGeometry() +{ + Oyster::Engine::PrepareForRendering::BindRenderTargets( Oyster::Resources::PipeLineResourses::GeometryTarget, 5 ); + Oyster::Shader::SetShaderEffect( Oyster::Resources::ShaderEffects::ModelEffect ); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::RenderGeometry(const Oyster::Render::Model* models,int count) +{ + //TODO: Add sorting to minimiza state changes + Render::Geometry( models, count, &Oyster::Resources::Buffers::CbufferVS, 2 ); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::EndRenderGeometry() +{ + //TODO: Actualy Render data from previous pass + Oyster::Engine::PrepareForRendering::BindRenderTargets( Oyster::Resources::PipeLineResourses::RtvNulls, 8, NULL ); + Oyster::Core::DeviceContext->PSSetShaderResources(0, 16, Oyster::Resources::PipeLineResourses::SrvNulls); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::InputPointLights(Oyster::Resources::BufferDefinitions::PointLightDescription *p, int nr) +{ + void* dest = Oyster::Resources::PipeLineResourses::Resources[1]->Map(); + memcpy(dest, p, sizeof(Oyster::Resources::BufferDefinitions::PointLightDescription) * nr ); + Oyster::Resources::PipeLineResourses::Resources[1]->Unmap(); +} + +void Oyster::Engine::Pipeline::Deffered_Lightning::RenderLightning() +{ + Oyster::Engine::PrepareForRendering::BindUAV( Oyster::Resources::PipeLineResourses::LightTarget, 4 ); + Oyster::Core::DeviceContext->CSSetShaderResources(0,5, Oyster::Resources::PipeLineResourses::GeometryOut); + Oyster::Resources::Buffers::CBufferPipelineCs.Apply(); + Oyster::Core::DeviceContext->CSSetShaderResources( 6, 4, Oyster::Resources::PipeLineResourses::ComputeResources ); + Oyster::Shader::Set::SetCompute( Oyster::Shader::Get::GetCompute("Pass0") ); + + Oyster::Core::DeviceContext->Dispatch( 49, 36, 1 ); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 16, Oyster::Resources::PipeLineResourses::SrvNulls ); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews( 0, 8, Oyster::Resources::PipeLineResourses::uavNULL, 0 ); + + //Blurr + //Blur( 2 ); + //Blur( 3 ); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 16, Oyster::Resources::PipeLineResourses::SrvNulls ); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews( 0, 8, Oyster::Resources::PipeLineResourses::uavNULL, 0 ); + + //prepare and render final pass + Oyster::Engine::PrepareForRendering::BindBackBufferAsUAV(); + Oyster::Shader::Set::SetCompute( Oyster::Shader::Get::GetCompute("Pass1") ); + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 4, Oyster::Resources::PipeLineResourses::LightOut ); + + Oyster::Core::DeviceContext->Dispatch( 49, 36, 1 ); + + //clean Pipeline + Oyster::Core::DeviceContext->CSSetShaderResources( 0, 16, Oyster::Resources::PipeLineResourses::SrvNulls ); + Oyster::Core::DeviceContext->CSSetUnorderedAccessViews( 0, 8, Oyster::Resources::PipeLineResourses::uavNULL, 0 ); +} + + +//States +int Oyster::Engine::States::GetNrOfSSAOSamples() +{ + return instance.States.NrOfSamples; +} + +void Oyster::Engine::States::SetNrOfSSAOSamples(int nr) +{ + instance.States.NrOfSamples = nr; +} + +int Oyster::Engine::States::GetSSAOSampleSpread() +{ + return instance.States.SampleSpread; +} + +void Oyster::Engine::States::SetSSAOSampleSpread(int spread) +{ + instance.States.SampleSpread = spread; +} + +int Oyster::Engine::States::GetMaxPointlights() +{ + return instance.States.NrOfPointlights; +} + +void Oyster::Engine::States::SetMaxPointlights(int nr) +{ + instance.States.NrOfPointlights = nr; +} \ No newline at end of file diff --git a/OysterGraphics/Engine.h b/OysterGraphics/Engine.h new file mode 100644 index 00000000..a9ef953c --- /dev/null +++ b/OysterGraphics/Engine.h @@ -0,0 +1,177 @@ +#pragma once + +#ifndef Engine_h +#define Engine_h + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros + +#include "EngineIncludes.h" + +namespace Oyster +{ + class Engine + { + private: + Engine(); + ~Engine(); + + public: + class Init + { + public: + struct Setup + { + struct + { + bool InitWindow; + LPCSTR appname; + LPCSTR classname; + HINSTANCE hinstance; + int nCmdShow; + WNDPROC wProc; + bool ManageWindow; + }Window; + struct + { + int NrOfBuffers; + bool MSAA_Quality; + bool Fullscreen; + bool SingleThreaded; + bool Reference; + bool ForceDX11; + bool GenerateDepthStencil; + bool BindDefault; + }Common; + //all but Window params have Default Values + Setup() + { + Common.NrOfBuffers=1; + Common.MSAA_Quality = false; + Common.Fullscreen = true; + Common.SingleThreaded = true; + Common.Reference = false; + Common.ForceDX11 = false; + Common.GenerateDepthStencil = true; + Common.BindDefault = true; + } + + }; + + static bool IsInstanced(); + + //Creates Device and DeviceContext, if not Initialized + static bool Instance(bool SingleThreaded=true,bool Reference=false,bool ForceDX11=false); + static bool HasSwapChain(); + + //Creates Swapchain, if not Aready Created + static bool CreateSwapChain(HWND Window, int NrofBuffers=1,bool MSAA_Quality=false,bool Fullscreen=true); + + //CreateWindow, if Not Already Created + static bool InitializeWindow(const LPCSTR appName, const LPCSTR className,const HINSTANCE &hInstance, const int &nCmdShow, WNDPROC wProc, bool HandleLoop = false ); + + //Performs a full initialization of a rendering pipeline, including a Window + static bool FullInit(const Setup& setup); + struct Buffers + { + static Buffer* CreateBuffer(const Buffer::BUFFER_INIT_DESC BufferDesc); + }; + private: + Init(); + ~Init(); + }; + + class States + { + public: + //SSAO Quality + static void SetNrOfSSAOSamples(int); + static int GetNrOfSSAOSamples(); + + //SSAO Frequency + static void SetSSAOSampleSpread(int); + static int GetSSAOSampleSpread(); + + //PointLights + static void SetMaxPointlights(int); + static int GetMaxPointlights(); + + + private: + States(); + ~States(); + }; + + class Render + { + public: + /// Render a number of models, setting the Per model data to the included cBuffer + /// specify NULL if no such data exists + static void Geometry(const Oyster::Render::Model* models,int count,Oyster::Buffer* cBufferEveryObject, int slot); + static void Text(std::string text, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos); + //static void TextBox(const Oyster::Render:: + + //ensure that a compatible 2D shadereffect is applied + static void ScreenQuad(ID3D11ShaderResourceView* srv, float ZPos=1); + + //ensure that a compatible 2D shadereffect is applied and that pos.z is between 0 and 1 + static void Sprite(ID3D11ShaderResourceView* srv, Oyster::Math::Float2 size, Oyster::Math::Float3 Pos); + + static void PresentScene(); + + private: + Render(); + ~Render(); + }; + + class PrepareForRendering + { + public: + //Binds several rendertargets and a depthstencil + static void BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets,ID3D11DepthStencilView* depth); + + //Binds several Rendertargest and a default depthstencil + static void BindRenderTargets(ID3D11RenderTargetView** RenderTargets,int NrOfTargets); + + //Binds the backbuffer and a depthstencil + static void BindBackBuffer(ID3D11DepthStencilView* depth); + + //Binds the backbuffer and a default depthstencil + static void BindBackBuffer(); + + //Binds the backbuffer to the compute shader + static void BindBackBufferAsUAV(); + + //binds several UAV to the computeshader + static void BindUAV(ID3D11UnorderedAccessView** uav, int NrOfUavs); + + //Clears the backbuffer and default depthstencil + static void ClearBackBuffer(Math::Float4 color); + + static void Begin2DRender(); + + static void Begin2DTextRender(); + }; + + class Pipeline + { + public: + class Deffered_Lightning + { + public: + //Basic Setup + static void NewFrame(const Float4& Color, const Matrix& View, const Matrix& Projection); + + //Geometry Pass + static void BeginRenderGeometry(); + static void RenderGeometry(const Oyster::Render::Model* models,int count); + static void EndRenderGeometry(); + + //Lightning Pass + static void InputPointLights(Oyster::Resources::BufferDefinitions::PointLightDescription *p, int NrOfPointlights ); + static void RenderLightning(); + }; + }; + }; +}; + +#endif \ No newline at end of file diff --git a/OysterGraphics/EngineIncludes.h b/OysterGraphics/EngineIncludes.h new file mode 100644 index 00000000..e1a763db --- /dev/null +++ b/OysterGraphics/EngineIncludes.h @@ -0,0 +1,38 @@ +//Oyster + +// Render +#include "Render\Model.h" +#include "Render\Camera.h" +#include "Render\TextBox.h" + +// Core +#include "Core\Core.h" +#include "Core\Buffer.h" + +// Shader +#include "Shader\Shader.h" + +// Math +#include "Math\OysterMath.h" + +// FileLoader +#include "FileLoader\ObjReader.h" + +// Windows +#include "Window\Window.h" + +// Input +#include "Input\InputController.h" + +// Collision +#include "Collision\Collision.h" + +// Game Definitions +#include "Game\OysterGame.h" + +// Resources +#include "Resourses\ShaderEffects.h" +#include "Resourses\Buffers.h" +#include "Resourses\PipelineResources.h" +#include "Resourses\GraphicsDefinitions.h" +#include "Resourses\Manager.h" \ No newline at end of file diff --git a/OysterGraphics/FileLoader/ObjReader.cpp b/OysterGraphics/FileLoader/ObjReader.cpp new file mode 100644 index 00000000..e4d12b91 --- /dev/null +++ b/OysterGraphics/FileLoader/ObjReader.cpp @@ -0,0 +1,268 @@ +#include "ObjReader.h" +#include "Utilities.h" +#include "..\Core\Core.h" +#include +#include + +using namespace std; +using namespace Oyster::FileLoaders; +using namespace Oyster; +using namespace Oyster::Math; + +ObjReader *ObjReader::LoadFile(std::string fileName, Oyster::Math::Float4x4 transform) +{ + static std::map cache; + + ObjReader *reader = NULL; + + if (cache.count(fileName)) + { + reader = cache[fileName]; + } + else + { + reader = new ObjReader(); + reader->ParseFile(fileName, transform); + + cache[fileName] = reader; + } + + return reader; +} + +ObjReader::ObjReader(void) +{ +} + + +ObjReader::~ObjReader(void) +{ +} + +void ObjReader::ParseFile(std::string fileName, Float4x4 transform) +{ + ifstream input; + input.open(fileName.c_str()); + + if(!input.is_open()) + { + return; + } + + string path; + Utility::String::extractDirPath(path,fileName,'\\'); + + std::vector VertexList; + std::vector vList; + std::vector nList; + std::vector uvList; + Vertex vertex1, vertex2, vertex3; + Float3 face[3]; + Float3 position, normal; + Float2 uv; + string s; + + while(!input.eof()) + { + getline(input,s); + int offset = (int)s.find(' '); + + if(offset!=-1) + { + string c = s.substr(0,offset); + + if(c=="v") + { + position = readVertex(offset,s); + vList.push_back(position); + } + else if(c=="vt") + { + uv = readUV(offset,s); + uvList.push_back(uv); + } + else if(c=="vn") + { + normal = readNormal(offset,s); + nList.push_back(normal); + } + else if(c=="f") + { + readFace(offset, s, face); + + vertex1.Position = vList[(int)face[0].x]; + vertex1.UV = uvList[(int)face[0].y]; + vertex1.Normal = nList[(int)face[0].z]; + + vertex2.Position = vList[(int)face[1].x]; + vertex2.UV = uvList[(int)face[1].y]; + vertex2.Normal = nList[(int)face[1].z]; + + vertex3.Position = vList[(int)face[2].x]; + vertex3.UV = uvList[(int)face[2].y]; + vertex3.Normal = nList[(int)face[2].z]; + + VertexList.push_back(vertex1); + VertexList.push_back(vertex3); + VertexList.push_back(vertex2); + } + else if(c=="mtllib") + { + this->materials = GetMaterials(path+s.substr(offset+1)); + } + } + } + + input.close(); + + this->numVertices = VertexList.size(); + this->vertices = new Vertex[this->numVertices]; + + for(size_t i=0;inumVertices;++i) + { + vertices[i].Position=Math::transformVector(Math::Float4(VertexList[i].Position,1),transform); + vertices[i].Normal=Math::transformVector(Math::Float4(VertexList[i].Normal,0),transform); + vertices[i].UV = VertexList[i].UV; + } +} + +void ObjReader::GetVertexData(Vertex **vertex,int &numVertex, std::map &Textures) +{ + numVertex=(int)this->numVertices; + (*vertex)=this->vertices; + Textures = this->materials; +} + +Float3 ObjReader::extract(std::string d) +{ + Float3 data; + int offset=(int)d.find('/'); + data.x=(float)atoi(d.substr(1,offset).c_str())-1; + + int newOffset = (int)d.find('/',offset+1); + string d2=d.substr(offset+1,newOffset-offset-1); + data.y=(float)atoi(d2.c_str())-1; + offset=newOffset; + + newOffset = (int)d.find('/',offset+1); + string d3=d.substr(offset+1,newOffset-offset-1); + data.z=(float)atoi(d3.c_str())-1; + + return data; +} + +Float3 ObjReader::readVertex(int offset,string s) +{ + int newOffset = (int)s.find(' ',offset+1); + Float3 vertex; + string d = s.substr(offset,newOffset-offset); + vertex.x = (float)atof(d.c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.y = (float)atof(s.substr(offset,newOffset-offset).c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.z = (float)-atof(s.substr(offset,newOffset-offset).c_str()); + + return vertex; +} + +Float2 ObjReader::readUV(int offset,string s) +{ + int newOffset = (int)s.find(' ',offset+1); + Float2 uv; + string d = s.substr(offset,newOffset-offset); + uv.x =(float)atof(d.c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + d = s.substr(offset,newOffset-offset); + uv.y =1- (float)atof(d.c_str()); + offset=newOffset; + + return uv; +} + +Float3 ObjReader::readNormal(int offset,string s) +{ + int newOffset = (int)s.find(' ',offset+1); + Float3 vertex; + string d = s.substr(offset,newOffset-offset); + vertex.x = (float)atof(d.c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.y = (float)atof(s.substr(offset,newOffset-offset).c_str()); + offset=newOffset; + + newOffset = (int)s.find(' ',offset+1); + vertex.z = (float)-atof(s.substr(offset,newOffset-offset).c_str()); + + return vertex; +} + +void ObjReader::readFace(int offset,string s, Oyster::Math::Float3 face[3]) +{ + int newOffset = (int)s.find(' ',offset+1); + string point1 = s.substr(offset,newOffset-offset); + + offset = newOffset; + newOffset = (int)s.find(' ',offset+1); + string point2 = s.substr(offset,newOffset-offset); + + offset = newOffset; + newOffset = (int)s.find(' ',offset+1); + string point3 = s.substr(offset,newOffset-offset); + + face[0] = extract(point1); + face[1] = extract(point2); + face[2] = extract(point3); +} + +std::map ObjReader::GetMaterials(std::string fileName) +{ + ifstream input; + input.open(fileName.c_str()); + + std::map materials; + ID3D11ShaderResourceView *srv; + string texture; + string s; + string path; + Utility::String::extractDirPath(path,fileName,'\\'); + if(!input.is_open()) + return materials; + + while(!input.eof()) + { + getline(input,s); + int offset = (int)s.find(' '); + if(offset!=-1) + { + string c = s.substr(0,offset); + if(c=="map_Kd") + { + texture = path+s.substr(offset+1); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device,texture.c_str(), NULL, NULL, &srv, NULL); + materials["Diffuse"] = srv; + } + if(c=="map_G") + { + texture = path+s.substr(offset+1); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device,texture.c_str(), NULL, NULL, &srv, NULL); + materials["Glow"] = srv; + } + if(c=="map_Ks") + { + texture = path+s.substr(offset+1); + D3DX11CreateShaderResourceViewFromFile(Oyster::Core::Device,texture.c_str(), NULL, NULL, &srv, NULL); + materials["Specular"] = srv; + } + } + } + input.close(); + + return materials; +} diff --git a/OysterGraphics/FileLoader/ObjReader.h b/OysterGraphics/FileLoader/ObjReader.h new file mode 100644 index 00000000..a846181e --- /dev/null +++ b/OysterGraphics/FileLoader/ObjReader.h @@ -0,0 +1,42 @@ +#pragma once +#include "..\Core\CoreIncludes.h" +#include "..\Math\OysterMath.h" + +namespace Oyster +{ + namespace FileLoaders + { + class ObjReader + { + public: + struct Vertex + { + Oyster::Math::Float3 Position; + Oyster::Math::Float3 Normal; + Oyster::Math::Float2 UV; + }; + + static ObjReader *LoadFile(std::string fileName, Oyster::Math::Float4x4 transform = Oyster::Math::Float4x4::identity); + + ObjReader(void); + ~ObjReader(void); + + void GetVertexData(Vertex **vertex,int &numVertex, std::map &textures); + + private: + Vertex *vertices; + size_t numVertices; + std::map materials; + + void ParseFile(std::string fileName, Oyster::Math::Float4x4 transform = Oyster::Math::Float4x4::identity); + + Oyster::Math::Float3 extract(std::string d); + Oyster::Math::Float3 readVertex(int offset,std::string s); + Oyster::Math::Float2 readUV(int offset,std::string s); + Oyster::Math::Float3 readNormal(int offset,std::string s); + void readFace(int offset,std::string s, Oyster::Math::Float3 face[3]); + + std::map GetMaterials(std::string fileName); + }; + } +} \ No newline at end of file diff --git a/OysterGraphics/Render/Camera.cpp b/OysterGraphics/Render/Camera.cpp new file mode 100644 index 00000000..19f85136 --- /dev/null +++ b/OysterGraphics/Render/Camera.cpp @@ -0,0 +1,157 @@ +#include "Camera.h" +//Hack: temp include, calc proj matrix properly later +#include "..\Core\CoreIncludes.h" + +using namespace Oyster; +using namespace Render; +using namespace Oyster::Math; +Camera::Camera(void) +{ +} + + +Camera::~Camera(void) +{ +} + +Math::Float3 Camera::GetPosition() {return pos;} +void Camera::SetPosition(Math::Float3 p){ pos=p;} + +//axis +Math::Float3 Camera::GetRight() {return right;} +Math::Float3 Camera::GetUp() {return up;} +Math::Float3 Camera::GetLook() {return look;} + +//frustrum +float Camera::GetNearZ(){return nearZ;} +float Camera::GetFarZ(){return farZ;} +float Camera::GetAspect(){return aspect;} +float Camera::GetFovY(){return fovY;} +float Camera::GetFovX(){return fovX;} + +//set frustrum +void Camera::SetLens(float fovY, float aspect, float zn, float zf) +{ + this->fovY=fovY; + this->aspect=aspect; + nearZ=zn; + farZ=zf; + D3DXMATRIX P; + D3DXMatrixPerspectiveFovLH(&P,fovY,aspect,zn,zf); + mProj = Math::Float4x4(P); +} + +//normal LookAt +void Camera::LookAt(Math::Float3 pos, Math::Float3 target, Math::Float3 worldUp) +{ + look=target; + up=worldUp; + this->pos=pos; + right = up.cross(look); +} + +//Get Matrices +Matrix Camera::View(){return mView;} +Matrix Camera::Proj(){return mProj;} +Matrix Camera::ViewProj() +{ + return (mView * mProj).transpose(); // edited by Dan 04-19 +} + +//Move Camera +//FIX: Multiply Add not working +//FIX: Single Float Duplicate Creation +void Camera::Strafe(float d) +{ + Math::Float3 s= Math::Float3(d,d,d); + pos= (Math::operator*(s,right)) + pos; +} +void Camera::Walk(float d) +{ + Math::Float3 s= Math::Float3(d,d,d); + pos= (Math::operator*(s,look)) + pos; +} +void Camera::Fly(float d) +{ + Math::Float3 s= Math::Float3(d,d,d); + pos= (Math::operator*(s,up)) + pos; +} + +//Rotate Camera +//FIX: Float3 * float4x4 +void Camera::Pitch(float angle) +{ + Matrix m; + Math::rotationMatrix(m,angle,right); + m = m.getAdjoint().getInverse(); + + up = (Math::Float4(up,0) * m).xyz; + look = (Math::Float4(look,0) * m).xyz; +} +void Camera::Yaw(float angle) +{ + + Matrix m; + Math::rotationMatrix(m,angle,up); + m = m.getAdjoint().getInverse(); + + right = (Math::Float4(right,0) * m).xyz; + look = (Math::Float4(look,0) * m).xyz; +} +void Camera::Roll(float angle) +{ + Matrix m; + Math::rotationMatrix(m, angle,look); + m = m.getAdjoint().getInverse(); + + up = (Math::Float4(up,0) * m).xyz; + right = (Math::Float4(right,0) * m).xyz; +} +void Camera::RotateY(float angle) +{ + Matrix m; + + Math::rotationMatrix_AxisY(m, angle); + + m = m.getAdjoint().getInverse(); + + up = (Math::Float4(up,0) * m).xyz; + look = (Math::Float4(look,0) * m).xyz; + right = (Math::Float4(right,0) * m).xyz; +} + +void Camera::UpdateViewMatrix() +{ + look.normalize(); + + up = look.cross(right); + up.normalize(); + + right = up.cross(look); + + float x = -pos.dot(right); + float y = -pos.dot(up); + float z = -pos.dot(look); + + mView.m[0][0] = right.x; + mView.m[1][0] = right.y; + mView.m[2][0] = right.z; + mView.m[3][0] = x; + + mView.m[0][1] = up.x; + mView.m[1][1] = up.y; + mView.m[2][1] = up.z; + mView.m[3][1] = y; + + mView.m[0][2] = look.x; + mView.m[1][2] = look.y; + mView.m[2][2] = look.z; + mView.m[3][2] = z; + + mView.m[0][3] = 0.0f; + mView.m[1][3] = 0.0f; + mView.m[2][3] = 0.0f; + mView.m[3][3] = 1.0f; +} + + diff --git a/OysterGraphics/Render/Camera.h b/OysterGraphics/Render/Camera.h new file mode 100644 index 00000000..cc558144 --- /dev/null +++ b/OysterGraphics/Render/Camera.h @@ -0,0 +1,61 @@ +#pragma once + +#include "..\Math\OysterMath.h" + +namespace Oyster +{ + namespace Render + { + class Camera + { + public: + Camera(void); + ~Camera(void); + + //position + Math::Float3 GetPosition(); + void SetPosition(Math::Float3); + + //axis + Math::Float3 GetRight(); + Math::Float3 GetUp(); + Math::Float3 GetLook(); + + //frustrum + float GetNearZ(); + float GetFarZ(); + float GetAspect(); + float GetFovY(); + float GetFovX(); + + //set frustrum + void SetLens(float fovY, float aspect, float zn, float zf); + + //normal LookAt + void LookAt(Math::Float3 pos, Math::Float3 target, Math::Float3 worldUp); + + //Get Matrices + Math::Matrix View(); + Math::Matrix Proj(); + Math::Matrix ViewProj(); + + //Move Camera + void Strafe(float d); + void Walk(float d); + void Fly(float d); + + //Rotate Camera + void Pitch(float angle); + void Yaw(float angle); + void Roll(float angle); + void RotateY(float angle); + + void UpdateViewMatrix(); + + private: + Math::Vector3 pos, right, up, look; + float nearZ,farZ,aspect,fovX,fovY; + Math::Matrix mView, mProj; + }; + } +} diff --git a/OysterGraphics/Render/Lights.h b/OysterGraphics/Render/Lights.h new file mode 100644 index 00000000..78c70838 --- /dev/null +++ b/OysterGraphics/Render/Lights.h @@ -0,0 +1,8 @@ +#pragma once +#include "Engine\Math\OysterMath.h" + +struct DirectionalLight +{ + Oyster::Math::Float4 Irradiance; + Oyster::Math::Float4 Direction; +}; \ No newline at end of file diff --git a/OysterGraphics/Render/Model.cpp b/OysterGraphics/Render/Model.cpp new file mode 100644 index 00000000..e69de29b diff --git a/OysterGraphics/Render/Model.h b/OysterGraphics/Render/Model.h new file mode 100644 index 00000000..c6f59050 --- /dev/null +++ b/OysterGraphics/Render/Model.h @@ -0,0 +1,32 @@ +#pragma once +#ifndef Mesh_h +#define Mesh_h + +//#include "../Engine.h" + + +//#include "..\Core\CoreIncludes.h" +//#include "..\Core\Buffer.h" +#include "OysterMath.h" +//#include "ICollideable.h" +#include "ModelInfo.h" + +using namespace Oyster::Math; + +namespace Oyster +{ + namespace Render + { + + struct Model + { + ModelInfo* info; + Float4x4 *World; + bool Visible; + }; + + + }; +}; + +#endif \ No newline at end of file diff --git a/OysterGraphics/Render/ModelInfo.h b/OysterGraphics/Render/ModelInfo.h new file mode 100644 index 00000000..a4702ca1 --- /dev/null +++ b/OysterGraphics/Render/ModelInfo.h @@ -0,0 +1,29 @@ +#pragma once +#ifndef MODELINFO_h +#define MODELINFO_h + +//#include "../Engine.h" + + +#include "..\Core\CoreIncludes.h" +#include "..\Core\Buffer.h" +//#include "OysterMath.h" +//#include "ICollideable.h" + +using namespace Oyster::Math; + +namespace Oyster +{ + namespace Render + { + struct ModelInfo + { + std::vector Material; + Oyster::Buffer Vertices,Indecies; + bool Indexed; + int VertexCount; + }; + }; +}; + +#endif \ No newline at end of file diff --git a/OysterGraphics/Render/TextBox.cpp b/OysterGraphics/Render/TextBox.cpp new file mode 100644 index 00000000..1cd162c6 --- /dev/null +++ b/OysterGraphics/Render/TextBox.cpp @@ -0,0 +1,165 @@ +#include "Textbox.h" +using namespace Oyster::Render; + +//int Textbox::NumTextfields=0; +Oyster::Buffer Textbox::TextBuffer; +int Textbox::NumLetters; +//std::vector Textbox::TextInstances; +ID3D11ShaderResourceView* Textbox::Texture=NULL; +bool Textbox::Init() +{ + //NumTextfields = 0; + //NumVertices = 0; + //HRESULT test=HRESULT_FAI + if(FAILED(CreateVertexBuffer())) + { + return false; + } + //update(_str, _pos); + return true; + //return true; +} +bool Textbox::SetTexture(const char* _file) +{ + if(FAILED(D3DX11CreateShaderResourceViewFromFileA(Oyster::Core::Device, _file, NULL, NULL, &Texture, NULL))) + { + return false; + } + return true; +} +bool Textbox::UpdateTextField(std::string _str) +{ + //DEPRECATED + //Update(_str); + return false; + /*UINT _id=TextInstances.size(); + //TextInstances.resize(_id+1); + Text2D newD; + TextInstances.push_back(newD); + if(FAILED(CreateTextfield(_id))) + { + return false; + } + Update(_id, _str, _pos); + TextInstances[_id].Visible=true; + TextInstances[_id].World=Float4x4::identity; + NumTextfields++; + return true;*/ +} + +HRESULT Textbox::CreateVertexBuffer() +{ + HRESULT result; + //Create vertices + /* + std::vector mVertices; + mVertices.resize(4); + D3DXVECTOR3 testloc=D3DXVECTOR3(0,0,0); + mVertices[0].pos = testloc+D3DXVECTOR3(0.0f, 0.0f, 0.0f); + mVertices[1].pos = testloc+D3DXVECTOR3(TEXT_SIZE, 0.0f, 0.0f); + mVertices[2].pos = testloc+D3DXVECTOR3(0.0f, TEXT_SIZE, 0.0f); + mVertices[3].pos = testloc+D3DXVECTOR3(TEXT_SIZE, TEXT_SIZE, 0.0f); + float normaloffset=(1.0f/TEXT_NR_LETTERS); + mVertices[0].uv=D3DXVECTOR2(normaloffset,1); + mVertices[1].uv=D3DXVECTOR2(0,1); + mVertices[2].uv=D3DXVECTOR2(normaloffset,0); + mVertices[3].uv=D3DXVECTOR2(0,0); + */ + + //Oyster::Buffer::BUFFER_INIT_DESC desc; + //desc.ElementSize=sizeof(TextData); + //desc.NumElements = mVertices.size(); + //desc.Type = Oyster::Buffer::BUFFER_TYPE::VERTEX_BUFFER; + //desc.Usage = Oyster::Buffer::BUFFER_USAGE::BUFFER_DEFAULT; + //desc.InitData = &mVertices[0]; + + //result=TextBuffer.Init(desc); + //NumVertices=mVertices.size(); + //TextInstances[_id].NumLetters=0; + /*Text2D tmp; + tmp.coff=0; + tmp.offset=0; + tmp.Pos=Float2(0,0);*/ + Oyster::Buffer::BUFFER_INIT_DESC desc; + desc.ElementSize=sizeof(Text2D); + desc.NumElements = MAX_LETTER_COUNT; + desc.Type = Oyster::Buffer::BUFFER_TYPE::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = 0; + result=TextBuffer.Init(desc); + NumLetters=0; + return result; +} +HRESULT Textbox::CreateTextfield(int _id) +{ + HRESULT result=E_FAIL; + /*if (TextInstances.size()>_id) + { + TextInstances[_id].NumLetters=0; + + Oyster::Buffer::BUFFER_INIT_DESC desc; + desc.ElementSize=sizeof(Text2D); + desc.NumElements = MAX_LETTER_COUNT; + desc.Type = Oyster::Buffer::BUFFER_TYPE::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = 0; + + result=TextInstances[_id].InstanceBuffer.Init(desc); + }*/ + return result; +} +void Textbox::Update(std::string _str, float _xscale) +{ + UINT instances=0; + Text2D tmpInst; + + void* dest = TextBuffer.Map(); + Text2D* dataView = reinterpret_cast(dest); + //tmpInst.charOffset=_pos; + for (unsigned int i=0; i<_str.length(); i++) + { + tmpInst.coff=(1.0f/TEXT_NR_LETTERS); + tmpInst.offset=(_str[i]-32); + tmpInst.Pos=i*(0.005f*_xscale); + //float tst=getCharID(_str[i]); + //tmpInst.offset=tst; + //tmpInst.charOffset.x=_pos.x-i*TEXT_SIZE; + //tmpInst.data=tst; + dataView[instances]=tmpInst; + instances++; + } + NumLetters=instances; + //TextInstances[_id].NumLetters=instances; + TextBuffer.Unmap(); +} +float Textbox::getCharID(char _in) +{ + //int charid=_in; + //float charid=((_in-'0')-32); + return ((_in-32)*(1.0f/TEXT_NR_LETTERS)); + //return _in-'0'; +} +void Textbox::Apply(int _id) +{ + //Check if the subset exists, so we don't try to pain something that isn't there resulting in a crash + //if (NumTextfields>_id) + //{ + //Oyster::Core::DeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + //Set the size of each vertex "jump", and the start point for the shader + //unsigned int strides[2]; + //offsets start at 0. + //unsigned int offsets[2]={0,0}; + + //Load the strides with the size of each type + //strides[0] = sizeof(TextData); + //strides[1] = sizeof(PerCharData); + + //Create an array which points to the buffers needed. + //ID3D11Buffer* bufferPointers[2]; + //bufferPointers[0] = TextBuffer; + //bufferPointers[1] = TextInstances[_id].InstanceBuffer; + //Load the vertex buffer into the shader + //Oyster::Core::DeviceContext->IASetVertexBuffers(0, 2, bufferPointers, strides, offsets); + //Get the basic info of the technique that's loaded + //} +} \ No newline at end of file diff --git a/OysterGraphics/Render/TextBox.h b/OysterGraphics/Render/TextBox.h new file mode 100644 index 00000000..633d0366 --- /dev/null +++ b/OysterGraphics/Render/TextBox.h @@ -0,0 +1,67 @@ +#pragma once + +#include "..\Engine.h" +const int MAX_LETTER_COUNT=60; +const int TEXT_NR_LETTERS=95; +const float TEXT_SIZE=2.5; +struct Text2D +{ + Oyster::Math::Float Pos; + int offset; + float coff; +}; +/*struct TextInstanceData +{ + Oyster::Buffer InstanceBuffer; + bool Visible; + int NumLetters; + Oyster::Math::Float4x4 World; +};*/ +/*struct TextData +{ + Oyster::Math::Float3 pos; + Oyster::Math::Float2 uv; +}; + +struct PerCharData +{ + float data; + Oyster::Math::Float3 charOffset; +}; +struct TextInstanceData +{ + Oyster::Buffer InstanceBuffer; + bool Visible; + int NumLetters; + Oyster::Math::Float4x4 World; +};*/ + +namespace Oyster +{ + namespace Render + { + class Textbox + { + private: + static float getCharID(char _in); + static HRESULT CreateVertexBuffer(); + static HRESULT CreateTextfield(int _id); + public: + //static Oyster::Buffer TextBuffer; + //static int NumVertices; + //static std::vector TextInstances; + static Oyster::Buffer TextBuffer; + static int NumLetters; + static ID3D11ShaderResourceView* Texture; + + static bool Init(); + static bool UpdateTextField(std::string _str); + static bool SetTexture(const char* _file); + //Updates a textbox with the certain id + static void Update(std::string _str, float _scale); + //Removes all old instances and recreates it with the input data + static HRESULT Reset(int _count, std::string* _str, Float3* _pos); + static void Apply(int _id); + }; + } +} diff --git a/OysterGraphics/Resourses/Buffers.cpp b/OysterGraphics/Resourses/Buffers.cpp new file mode 100644 index 00000000..e36b3790 --- /dev/null +++ b/OysterGraphics/Resourses/Buffers.cpp @@ -0,0 +1,44 @@ +#include "Buffers.h" + +namespace Oyster +{ + namespace Resources + { + Buffer Buffers::V2DSprites = Buffer(); + Buffer Buffers::CbufferVS = Buffer(); + Buffer Buffers::CBufferGs = Buffer(); + Buffer Buffers::CBufferPipelineCs = Buffer(); + + void Buffers::Init() + { + Buffer::BUFFER_INIT_DESC desc; + + desc.ElementSize=sizeof(Math::Float2); + desc.NumElements=1; + desc.Type = Buffer::BUFFER_TYPE::VERTEX_BUFFER; + desc.Usage = Buffer::BUFFER_USAGE::BUFFER_DEFAULT; + desc.InitData = &Math::Float2(0,0); + + V2DSprites.Init(desc); + + desc.Type=Buffer::BUFFER_TYPE::CONSTANT_BUFFER_VS; + desc.Usage = Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.ElementSize=sizeof(Math::Float4x4); + desc.InitData=0; + + CbufferVS.Init(desc); + + desc.Type = Buffer::BUFFER_TYPE::CONSTANT_BUFFER_GS; + + CBufferGs.Init(desc); + + desc.ElementSize=sizeof(Oyster::Resources::BufferDefinitions::LightStructureBuffer); + desc.NumElements=1; + desc.Type = Buffer::BUFFER_TYPE::CONSTANT_BUFFER_CS; + desc.Usage = Buffer::BUFFER_USAGE::BUFFER_CPU_WRITE_DISCARD; + desc.InitData = NULL; + + CBufferPipelineCs.Init(desc); + } + } +} \ No newline at end of file diff --git a/OysterGraphics/Resourses/Buffers.h b/OysterGraphics/Resourses/Buffers.h new file mode 100644 index 00000000..ec445b6c --- /dev/null +++ b/OysterGraphics/Resourses/Buffers.h @@ -0,0 +1,22 @@ +#pragma once + +#include "../EngineIncludes.h" + +namespace Oyster +{ + namespace Resources + { + struct Buffers + { + static Buffer V2DSprites; + + static Buffer CbufferVS; + + static Buffer CBufferGs; + + static Buffer CBufferPipelineCs; + + static void Init(); + }; + } +} \ No newline at end of file diff --git a/OysterGraphics/Resourses/GraphicsDefinitions.h b/OysterGraphics/Resourses/GraphicsDefinitions.h new file mode 100644 index 00000000..12a85d5f --- /dev/null +++ b/OysterGraphics/Resourses/GraphicsDefinitions.h @@ -0,0 +1,34 @@ +#pragma once + + +#include "..\EngineIncludes.h" + +namespace Oyster +{ + namespace Resources + { + + namespace BufferDefinitions + { + struct LightStructureBuffer + { + ::Oyster::Math::Float4x4 viewMatrix, projectionMatrix; + ::LinearAlgebra::Vector3 numDispatches; + unsigned int reservedPadding; + }; + + struct ScreenTileFrustrum + { + ::Oyster::Math::Float rawElement[6 * 4]; + }; + + class PointLightDescription + { + public: + struct{ ::Oyster::Math::Float3 center; ::Oyster::Math::Float radius; } pos; + ::Oyster::Math::Float3 color; + ::Oyster::Math::Float intensty; + }; + }; + } +} \ No newline at end of file diff --git a/OysterGraphics/Resourses/Manager.cpp b/OysterGraphics/Resourses/Manager.cpp new file mode 100644 index 00000000..c4132fba --- /dev/null +++ b/OysterGraphics/Resourses/Manager.cpp @@ -0,0 +1,47 @@ +#include "Manager.h" + +std::unordered_map< std::string, Oyster::Render::ModelInfo*> Oyster::Resources::Manager::loadedModels = std::unordered_map< std::string, Oyster::Render::ModelInfo*>(); + +Oyster::Render::Model* Oyster::Resources::Manager::LoadModel(std::string Filename, Matrix Scale) +{ + //TODO: Add redundncy sheck, to ensure not recreating model + + //Loop to find filename + + //If found Return Model + + //else Create Model + + Oyster::FileLoaders::ObjReader *reader = Oyster::FileLoaders::ObjReader::LoadFile(Filename, Scale); + Oyster::FileLoaders::ObjReader::Vertex** vertex = new Oyster::FileLoaders::ObjReader::Vertex*[1]; + int vcount; + std::map textures; + reader->GetVertexData( vertex, vcount, textures ); + + Oyster::Buffer::BUFFER_INIT_DESC desc; + desc.ElementSize=sizeof(Oyster::FileLoaders::ObjReader::Vertex); + desc.NumElements = vcount; + desc.InitData = *vertex; + desc.Type = Oyster::Buffer::VERTEX_BUFFER; + desc.Usage = Oyster::Buffer::BUFFER_DEFAULT; + + ID3D11ShaderResourceView *srv = textures["Diffuse"]; + + Oyster::Render::ModelInfo* m = new Oyster::Render::ModelInfo(); + + m->Vertices = *(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + m->VertexCount = vcount; + m->Material.push_back(srv); + srv = textures["Specular"]; + m->Material.push_back(srv); + srv = textures["Glow"]; + m->Material.push_back(srv); + m->Indexed=false; + + Oyster::Render::Model* model = new Oyster::Render::Model(); + model->info=m; + model->Visible = true; + model->World = &Oyster::Math::Float4x4(Oyster::Math::Float4x4::identity); + return model; +} + diff --git a/OysterGraphics/Resourses/Manager.h b/OysterGraphics/Resourses/Manager.h new file mode 100644 index 00000000..6de367e3 --- /dev/null +++ b/OysterGraphics/Resourses/Manager.h @@ -0,0 +1,20 @@ +#pragma once + +#include "../EngineIncludes.h" +#include + +namespace Oyster +{ + namespace Resources + { + struct Manager + { + //Expects to be deleted either trough manager or after a clean + static Oyster::Render::Model* LoadModel(std::string Filename, Matrix Scale); + static void Clean(); + + private: + static std::unordered_map< std::string, Oyster::Render::ModelInfo*> loadedModels; + }; + } +} \ No newline at end of file diff --git a/OysterGraphics/Resourses/PipelineResources.cpp b/OysterGraphics/Resourses/PipelineResources.cpp new file mode 100644 index 00000000..291c3c7c --- /dev/null +++ b/OysterGraphics/Resourses/PipelineResources.cpp @@ -0,0 +1,228 @@ +#include "PipelineResources.h" + +using namespace Oyster::Resources; + +ID3D11UnorderedAccessView* PipeLineResourses::TempUav = 0; +ID3D11ShaderResourceView* PipeLineResourses::TempSrv = 0; + +ID3D11ShaderResourceView* PipeLineResourses::GeometryOut[5] = {0}; +ID3D11RenderTargetView* PipeLineResourses::GeometryTarget[5] = {0}; + +ID3D11ShaderResourceView* PipeLineResourses::ComputeResources[4] = {0}; +Oyster::Buffer* PipeLineResourses::Resources[2] = {0}; + +ID3D11ShaderResourceView* PipeLineResourses::LightOut[4] = {0}; +ID3D11UnorderedAccessView* PipeLineResourses::LightTarget[4] = {0}; + +ID3D11RenderTargetView* PipeLineResourses::RtvNulls[16] = {0}; +ID3D11ShaderResourceView* PipeLineResourses::SrvNulls[16] = {0}; +ID3D11UnorderedAccessView* PipeLineResourses::uavNULL[16] = {0}; + +Oyster::Collision::Frustrum* PipeLineResourses::SubFrustrums = 0; +int PipeLineResourses::FrustrumSize = 0; +LinearAlgebra::Vector3 PipeLineResourses::FrustrumDimensions = LinearAlgebra::Vector3(); + +Oyster::Resources::BufferDefinitions::LightStructureBuffer PipeLineResourses::LightData = Oyster::Resources::BufferDefinitions::LightStructureBuffer(); + +void PipeLineResourses::Init() +{ + InitGeometry(); + + InitSSAOData(); + InitSubFrustrums(); + InitPointLights(); + InitLightData(); + + InitLighting(); +} + +void PipeLineResourses::InitGeometry() +{ + D3D11_TEXTURE2D_DESC Tdesc; + Tdesc.Width = Oyster::Window::Size.left; + Tdesc.Height = Oyster::Window::Size.bottom; + Tdesc.MipLevels = Tdesc.ArraySize = 1; + Tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + Tdesc.SampleDesc.Count = 1; + Tdesc.SampleDesc.Quality=0; + Tdesc.Usage = D3D11_USAGE_DEFAULT; + Tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + Tdesc.CPUAccessFlags = 0; + Tdesc.MiscFlags = 0; + + ID3D11Texture2D *pTexture; + HRESULT hr; + + //Geometry stage resourses + for( int i = 0; i < 5; ++i ) + { + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView(pTexture,0,&GeometryOut[i]); + hr = Oyster::Core::Device->CreateRenderTargetView(pTexture,0,&GeometryTarget[i]); + pTexture->Release(); + } +} + +void PipeLineResourses::InitSSAOData() +{ + //create Half Spheres and Random Data + + Oyster::Buffer::BUFFER_INIT_DESC desc; + HRESULT hr; + + int NrOfSamples = Oyster::Engine::States::GetNrOfSSAOSamples(); + int SampleSpread = Oyster::Engine::States::GetSSAOSampleSpread(); + + Oyster::Math::Vector3* kernel = new Oyster::Math::Vector3[ NrOfSamples ]; + Oyster::Math::Vector3* random = new Oyster::Math::Vector3[ SampleSpread ]; + + for(int i = 0; i < NrOfSamples; ++i) + { + kernel[i] = Oyster::Math::Vector3::null; + while( kernel[i] == Oyster::Math::Vector3::null ) + { + kernel[i] = Oyster::Math::Vector3( + (float)rand() / (RAND_MAX + 1) * (1 - -1) + -1, + (float)rand() / (RAND_MAX + 1) * (1 - -1) + -1, + (float)rand() / (RAND_MAX + 1) * (1 - 0) + 0); + } + kernel[i].normalize(); + + float scale = float(i) / float(NrOfSamples); + scale = (0.1f*(1 - scale * scale) + 1.0f *( scale * scale)); + kernel[i] *= scale; + + if( i < SampleSpread) + { + random[i] = Oyster::Math::Vector3::null; + while( random[i] == Oyster::Math::Vector3::null ) + { + random[i] = Oyster::Math::Vector3( + (float)rand() / (RAND_MAX + 1) * (1 - -1)+ -1, + (float)rand() / (RAND_MAX + 1) * (1 - -1)+ -1, + 0.0f); + } + random[i].normalize(); + } + } + + + D3D11_TEXTURE1D_DESC T1desc; + T1desc.Width = NrOfSamples; + T1desc.MipLevels = T1desc.ArraySize = 1; + T1desc.Format = DXGI_FORMAT_R32G32B32_FLOAT; + T1desc.Usage = D3D11_USAGE_DEFAULT; + T1desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + T1desc.CPUAccessFlags = 0; + T1desc.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA sphere; + sphere.pSysMem = kernel; + + D3D11_SUBRESOURCE_DATA rnd; + rnd.pSysMem = random; + + + ID3D11Texture1D *pTexture1[2]; + + hr = Oyster::Core::Device->CreateTexture1D( &T1desc, &sphere, &pTexture1[0] ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture1[0], 0, &ComputeResources[3] ); + pTexture1[0]->Release(); + delete[] kernel; + + T1desc.Width = SampleSpread; + hr = Oyster::Core::Device->CreateTexture1D( &T1desc, &rnd, &pTexture1[1] ); + hr = Oyster::Core::Device->CreateShaderResourceView( (pTexture1[1]), 0, &ComputeResources[2] ); + pTexture1[1]->Release(); + delete[] random; +} + +void PipeLineResourses::InitSubFrustrums() +{ + FrustrumDimensions.x = (::Oyster::Window::Size.left + 15U) / 16U; + FrustrumDimensions.y = (::Oyster::Window::Size.bottom + 15U) / 16U; + FrustrumDimensions.z = 1; + FrustrumSize = FrustrumDimensions.x * FrustrumDimensions.y * FrustrumDimensions.z; + if(SubFrustrums!=0) + delete[] SubFrustrums; + SubFrustrums = new Frustrum[ FrustrumSize ]; + + Oyster::Buffer::BUFFER_INIT_DESC desc; + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + + //buffer description for SubFrustrums + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::STRUCTURED_BUFFER; + desc.ElementSize = sizeof( ::Oyster::Resources::BufferDefinitions::ScreenTileFrustrum); + desc.NumElements = FrustrumSize; + desc.InitData = NULL; + + //create matching srv + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = FrustrumSize; + + PipeLineResourses::Resources[0] = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + HRESULT hr = Oyster::Core::Device->CreateShaderResourceView( *PipeLineResourses::Resources[0], &srvDesc, &Oyster::Resources::PipeLineResourses::ComputeResources[0] ); +} + +void PipeLineResourses::InitPointLights() +{ + D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; + Oyster::Buffer::BUFFER_INIT_DESC desc; + HRESULT hr; + + //buffer description for pointlight + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::STRUCTURED_BUFFER; + desc.ElementSize = sizeof(Oyster::Resources::BufferDefinitions::PointLightDescription); + desc.NumElements = Oyster::Engine::States::GetMaxPointlights(); + desc.InitData = NULL; + + PipeLineResourses::Resources[1] = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + //create matching srv + srvDesc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.FirstElement = 0; + srvDesc.Buffer.NumElements = Oyster::Engine::States::GetMaxPointlights(); + + hr = Oyster::Core::Device->CreateShaderResourceView( *PipeLineResourses::Resources[1], &srvDesc, &Oyster::Resources::PipeLineResourses::ComputeResources[1] ); +} + +void PipeLineResourses::InitLightData() +{ + LightData.numDispatches = FrustrumDimensions; +} + +void PipeLineResourses::InitLighting() +{ + D3D11_TEXTURE2D_DESC Tdesc; + Tdesc.Width = Oyster::Window::Size.left; + Tdesc.Height = Oyster::Window::Size.bottom; + Tdesc.MipLevels = Tdesc.ArraySize = 1; + Tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + Tdesc.SampleDesc.Count = 1; + Tdesc.SampleDesc.Quality=0; + Tdesc.Usage = D3D11_USAGE_DEFAULT; + Tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; + Tdesc.CPUAccessFlags = 0; + Tdesc.MiscFlags = 0; + + ID3D11Texture2D *pTexture; + HRESULT hr; + for(int i = 0; i < 4; ++i ) + { + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture, 0, &(LightOut[i]) ); + hr = Oyster::Core::Device->CreateUnorderedAccessView( pTexture, 0, &(LightTarget[i]) ); + pTexture->Release(); + } + + hr = Oyster::Core::Device->CreateTexture2D( &Tdesc, NULL, &pTexture ); + hr = Oyster::Core::Device->CreateShaderResourceView( pTexture, 0, &TempSrv ); + hr = Oyster::Core::Device->CreateUnorderedAccessView( pTexture, 0, &TempUav ); + pTexture->Release(); +} \ No newline at end of file diff --git a/OysterGraphics/Resourses/PipelineResources.h b/OysterGraphics/Resourses/PipelineResources.h new file mode 100644 index 00000000..b7f4a858 --- /dev/null +++ b/OysterGraphics/Resourses/PipelineResources.h @@ -0,0 +1,66 @@ +#pragma once + +#ifndef PipeLineResources_H +#define PipeLineResources_H + +#include "..\EngineIncludes.h" + +namespace Oyster +{ + namespace Resources + { + struct PipeLineResourses + { + //0 = Diffuse + //1 = Specular + //2 = Glow + //3 = Pos + //4 = Normal + static ID3D11ShaderResourceView* GeometryOut[5]; + static ID3D11RenderTargetView* GeometryTarget[5]; + + + //0 = TileBuffer + //1 = PointList + //2 = Random + //3 = Sphere + static ID3D11ShaderResourceView* ComputeResources[4]; + static Oyster::Buffer* Resources[2]; + + + //0 = Diffuse + //1 = Specular + //2 = Glow + //3 = SSAO + static ID3D11ShaderResourceView* LightOut[4]; + static ID3D11UnorderedAccessView* LightTarget[4]; + + //0 = BlurTempStorage + static ID3D11UnorderedAccessView* TempUav; + static ID3D11ShaderResourceView* TempSrv; + + static ID3D11RenderTargetView* RtvNulls[16]; + static ID3D11ShaderResourceView* SrvNulls[16]; + static ID3D11UnorderedAccessView* uavNULL[16]; + + static Oyster::Collision::Frustrum* SubFrustrums; + static int FrustrumSize; + static LinearAlgebra::Vector3 FrustrumDimensions; + + static Oyster::Resources::BufferDefinitions::LightStructureBuffer LightData; + + static void Init(); + + static void InitGeometry(); + + static void InitSSAOData(); + static void InitSubFrustrums(); + static void InitPointLights(); + static void InitLightData(); + + static void InitLighting(); + }; + } +} + +#endif \ No newline at end of file diff --git a/OysterGraphics/Resourses/ShaderEffects.cpp b/OysterGraphics/Resourses/ShaderEffects.cpp new file mode 100644 index 00000000..8e09956b --- /dev/null +++ b/OysterGraphics/Resourses/ShaderEffects.cpp @@ -0,0 +1,100 @@ +#include "ShaderEffects.h" + +namespace Oyster +{ + namespace Resources + { + Shader::ShaderEffect ShaderEffects::BasicSprite = Shader::ShaderEffect(); + Shader::ShaderEffect ShaderEffects::Text2DEffect = Shader::ShaderEffect(); + Shader::ShaderEffect ShaderEffects::ModelEffect = Shader::ShaderEffect(); + + void ShaderEffects::Init() + { + BasicSprite.IAStage.Topology = D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + BasicSprite.Shaders.Vertex = Oyster::Shader::Get::GetVertex("2D"); + BasicSprite.Shaders.Geometry = Oyster::Shader::Get::GetGeometry("2D"); + BasicSprite.Shaders.Pixel = Oyster::Shader::Get::GetPixel("Texture0"); + + D3D11_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable=false; + blendDesc.IndependentBlendEnable=false; + blendDesc.RenderTarget[0].BlendEnable=true; + + blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + + blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; + blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_MAX; + + blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; + + ID3D11BlendState* blender; + + Oyster::Core::Device->CreateBlendState(&blendDesc,&blender); + + BasicSprite.RenderStates.BlendState = blender; + + ID3D11InputLayout* layout; + + Oyster::Shader::CreateInputLayout(SpriteVertexDesc,1,Oyster::Shader::Get::GetVertex("2D"),layout); + + BasicSprite.IAStage.Layout = layout; + + Text2DEffect.IAStage.Topology=D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; + Text2DEffect.Shaders.Vertex = Oyster::Shader::Get::GetVertex("Text"); + Text2DEffect.Shaders.Geometry = Oyster::Shader::Get::GetGeometry("Text"); + Text2DEffect.Shaders.Pixel = Oyster::Shader::Get::GetPixel("Texture0"); + + Oyster::Shader::CreateInputLayout(Text2DDesc,3,Oyster::Shader::Get::GetVertex("Text"),layout); + + Text2DEffect.IAStage.Layout = layout; + + blendDesc.AlphaToCoverageEnable = true; + Oyster::Core::Device->CreateBlendState(&blendDesc,&blender); + Text2DEffect.RenderStates.BlendState = blender; + + ModelEffect.IAStage.Topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + Oyster::Shader::CreateInputLayout(ModelDesc,3,Oyster::Shader::Get::GetVertex("OBJ"),layout); + ModelEffect.IAStage.Layout = layout; + + ModelEffect.Shaders.Vertex = Oyster::Shader::Get::GetVertex("OBJ"); + ModelEffect.Shaders.Pixel = Oyster::Shader::Get::GetPixel("OBJDEF"); + + Oyster::Buffer::BUFFER_INIT_DESC desc; + + desc.ElementSize=sizeof(Oyster::Math::Float4x4); + desc.NumElements = 1; + desc.Usage = Oyster::Buffer::BUFFER_CPU_WRITE_DISCARD; + desc.Type = Oyster::Buffer::CONSTANT_BUFFER_VS; + desc.InitData = NULL; + + ModelEffect.CBuffers.Vertex.push_back(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + ModelEffect.CBuffers.Vertex.push_back(Oyster::Engine::Init::Buffers::CreateBuffer(desc)); + + //use Oyster::Resources::Buffers::CbufferVS for per object data + //perObject = Oyster::Engine::Init::Buffers::CreateBuffer(desc); + + } + + D3D11_INPUT_ELEMENT_DESC ShaderEffects::SpriteVertexDesc[1] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + D3D11_INPUT_ELEMENT_DESC ShaderEffects::Text2DDesc[3] = + { + {"Position",0, DXGI_FORMAT_R32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"Offset",0, DXGI_FORMAT_R32_SINT, 0, 4, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"CharOffset",0, DXGI_FORMAT_R32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + + D3D11_INPUT_ELEMENT_DESC ShaderEffects::ModelDesc[3] = + { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + }; + } +} \ No newline at end of file diff --git a/OysterGraphics/Resourses/ShaderEffects.h b/OysterGraphics/Resourses/ShaderEffects.h new file mode 100644 index 00000000..7377bb7f --- /dev/null +++ b/OysterGraphics/Resourses/ShaderEffects.h @@ -0,0 +1,23 @@ +#pragma once + +#include "../Engine.h" +#include "Buffers.h" + +namespace Oyster +{ + namespace Resources + { + struct ShaderEffects + { + static Oyster::Shader::ShaderEffect BasicSprite; + static Oyster::Shader::ShaderEffect Text2DEffect; + static Oyster::Shader::ShaderEffect ModelEffect; + + static void Init(); + + static D3D11_INPUT_ELEMENT_DESC SpriteVertexDesc[1]; + static D3D11_INPUT_ELEMENT_DESC Text2DDesc[3]; + static D3D11_INPUT_ELEMENT_DESC ModelDesc[3]; + }; + } +} \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/2D.hlsl b/OysterGraphics/Shader/HLSL/2D.hlsl new file mode 100644 index 00000000..2ea2afc2 --- /dev/null +++ b/OysterGraphics/Shader/HLSL/2D.hlsl @@ -0,0 +1,51 @@ +struct Vertex2DIn +{ + float2 Pos : Position; +}; + +cbuffer EveryObject2D : register(c0) +{ + float4x4 Translation; +}; + +SamplerState LinearSampler : register(s0); + +struct Pixel2DIn +{ + float4 Pos : SV_Position; + float2 Uv : TEXCOORD; +}; + +Texture2D Material : register(t0); + +float4 ApplyMaterial0(Pixel2DIn input) : SV_Target0 +{ + return Material.Sample(LinearSampler,input.Uv); +} + + +Vertex2DIn PassThrough(Vertex2DIn input) +{ + return input; +} + +[maxvertexcount(4)] +void PointToQuad(point Vertex2DIn input[1],inout TriangleStream Quads) +{ + Pixel2DIn output; + output.Pos = mul(float4(-1,-1,0,1) ,Translation); + output.Uv = float2(0,1); + Quads.Append(output); + + output.Pos = mul(float4(-1,1,0,1), Translation); + output.Uv = float2(0,0); + Quads.Append(output); + + output.Pos = mul(float4(1,-1,0,1), Translation); + output.Uv = float2(1,1); + Quads.Append(output); + + output.Pos = mul(float4(1,1,0,1), Translation); + output.Uv = float2(1,0); + Quads.Append(output); +} \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/BasicDemo.hlsl b/OysterGraphics/Shader/HLSL/BasicDemo.hlsl new file mode 100644 index 00000000..bce85017 --- /dev/null +++ b/OysterGraphics/Shader/HLSL/BasicDemo.hlsl @@ -0,0 +1,22 @@ +cbuffer everyFrame : register(c0) +{ + matrix VP; +} + +cbuffer everyObject : register(c1) +{ + matrix world; +} + +Texture2D Diffuse :register(t0); + +float4 VSScene(float4 input : POSITION) : SV_Position +{ + //return input; + return mul(input,VP); +} + +float4 PSScene(float4 input : SV_Position) : SV_Target0 +{ + return float4(0,1,0,1); +} \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/CollisionMethods.hlsl b/OysterGraphics/Shader/HLSL/CollisionMethods.hlsl new file mode 100644 index 00000000..a869e1b5 --- /dev/null +++ b/OysterGraphics/Shader/HLSL/CollisionMethods.hlsl @@ -0,0 +1,52 @@ +#ifndef COLLISIONMETHODS_HLSL +#define COLLISIONMETHODS_HLSL + +struct Sphere +{ + float3 center; + float radius; +}; + +struct Plane +{ + float3 normal; + float phasing; +}; + +struct Frustrum +{ + Plane leftPlane, rightPlane, bottomPlane, topPlane, nearPlane, farPlane; +}; + +bool intersects( uniform Frustrum f, uniform Sphere s ) +{ + float connectOffset; + + connectOffset = dot( f.leftPlane.normal, s.center ); + connectOffset += f.leftPlane.phasing; + if( connectOffset < -s.radius ) return false; + + connectOffset = dot( f.rightPlane.normal, s.center ); + connectOffset += f.rightPlane.phasing; + if( connectOffset < -s.radius ) return false; + + connectOffset = dot( f.bottomPlane.normal, s.center ); + connectOffset += f.bottomPlane.phasing; + if( connectOffset < -s.radius ) return false; + + connectOffset = dot( f.topPlane.normal, s.center ); + connectOffset += f.topPlane.phasing; + if( connectOffset < -s.radius ) return false; + + connectOffset = dot( f.nearPlane.normal, s.center ); + connectOffset += f.nearPlane.phasing; + if( connectOffset < -s.radius ) return false; + + connectOffset = dot( f.farPlane.normal, s.center ); + connectOffset += f.farPlane.phasing; + if( connectOffset < -s.radius ) return false; + + return true; +} + +#endif \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/Deffered.hlsl b/OysterGraphics/Shader/HLSL/Deffered.hlsl new file mode 100644 index 00000000..bd8b219e --- /dev/null +++ b/OysterGraphics/Shader/HLSL/Deffered.hlsl @@ -0,0 +1,85 @@ +Texture2D Diffuse : register(t0); +Texture2D Glow : register(t1); + +RWTexture2D Output : register(u0); + +cbuffer BlurrData : register(c0) +{ + static const int blurRadius = 5; + static const float Weights[11] = + { + 0.05f,0.05f,0.1f,0.1f,0.1f,0.2f,0.1f,0.1f,0.1f,0.05f,0.05f + }; +}; + +[numthreads(32,32,1)] +void TryCompute(uint3 ThreadID : SV_DispatchThreadID) +{ + Output[ThreadID.xy] = Diffuse[ThreadID.xy]*0.5f+Glow[ThreadID.xy]*Glow[ThreadID.xy].w; +} + +#define N 128 +#define gSize (N+2*blurRadius) +groupshared float4 gCache[gSize]; + +[numthreads(N,1,1)] +void BlurrHor(int3 ThreadID : SV_DispatchThreadID, int3 gThreadID : SV_GroupThreadID) +{ + + if(gThreadID.x < blurRadius) + { + int x = max(ThreadID.x-blurRadius,0); + gCache[gThreadID.x] = Diffuse[int2(x,ThreadID.y)]; + } + if(gThreadID.x >= N-blurRadius) + { + int x = min(ThreadID.x+blurRadius,Diffuse.Length.x-1); + gCache[gThreadID.x+2*blurRadius] = Diffuse[int2(x,ThreadID.y)]; + } + gCache[gThreadID.x+blurRadius] = Diffuse[min(ThreadID.xy,Diffuse.Length.xy-1)]; + + GroupMemoryBarrierWithGroupSync(); + + float4 blurCol = float4(0,0,0,0); + + [unroll] + for(int i = -blurRadius; i <= blurRadius;++i) + { + int k = gThreadID.x + blurRadius + i; + blurCol +=Weights[i + blurRadius] * gCache[k]; + } + + Output[ThreadID.xy] = blurCol; + //Output[ThreadID.xy] = Diffuse[((ThreadID.xy))]; +} + +[numthreads(1,N,1)] +void BlurrVert(int3 ThreadID : SV_DispatchThreadID, int3 gThreadID : SV_GroupThreadID) +{ + + if(gThreadID.y < blurRadius) + { + int y = max(ThreadID.y-blurRadius,0); + gCache[gThreadID.y] = Diffuse[int2(ThreadID.x,y)]; + } + if(gThreadID.y >= N-blurRadius) + { + int y = min(ThreadID.y+blurRadius,Diffuse.Length.y-1); + gCache[gThreadID.y+2*blurRadius] = Diffuse[int2(ThreadID.x,y)]; + } + gCache[gThreadID.y+blurRadius] = Diffuse[min(ThreadID.xy,Diffuse.Length.xy-1)]; + + GroupMemoryBarrierWithGroupSync(); + + float4 blurCol = float4(0,0,0,0); + + [unroll] + for(int i = -blurRadius; i <= blurRadius;++i) + { + int k = gThreadID.y + blurRadius + i; + blurCol +=Weights[i + blurRadius] * gCache[k]; + } + + Output[ThreadID.xy] = blurCol; + //Output[ThreadID.xy] = Diffuse[((ThreadID.xy))]; +} \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/Lazer.hlsl b/OysterGraphics/Shader/HLSL/Lazer.hlsl new file mode 100644 index 00000000..dc656818 --- /dev/null +++ b/OysterGraphics/Shader/HLSL/Lazer.hlsl @@ -0,0 +1,129 @@ +struct VertexIn +{ + float3 Pos : Position; +}; + +cbuffer EveryObject2D : register(c0) +{ + float4x4 VP; +}; + +struct Pixel2DIn +{ + float4 Pos : SV_Position; + float2 Uv : TEXCOORD; +}; + +const static float Width = 5.0f; + +VertexIn PassThrough(VertexIn input) +{ + return input; +} + +[maxvertexcount(16)] +void Lazer(line VertexIn input[2],inout TriangleStream Quads) +{ + //build coordinate system + float3 r =normalize(input[1].Pos-input[0].Pos); + float3 s = abs(r); + //set s ortogonal to r + if(s.x 0.0f ) + { // calculating and adding the SpecularCoefficient + coeff = max( dot( reflect(-toLightVecV, normalV), normalize(-pixelPosV) ), 0.0f ); + specularPixel += illum * pow( coeff, specularGloss ); + } + +} + +// ------------------ old below +/* +struct Medium +{ + float3 ambienceLuminosity; + float attenuationCoeff; +}; + +struct Light +{ + matrix worldToLightVolume; + float3 luminosity; + float spreadCoeff; + float4 orientation; +}; + +// returns light density per rgb channel +float3 calcLightDensity( uniform float rangeW, uniform Light light, uniform Medium enviroment ) +{ return light.luminosity / ( (enviroment.attenuationCoeff * rangeW) + (light.spreadCoeff * pow(rangeW, 2.0f)) ); } + +// returns light density per rgb channel +float3 calcLightDensity( uniform float rangeW, uniform Light light ) +{ return light.luminosity / ( rangeW + (light.spreadCoeff * pow(rangeW, 2.0f)) ); } + +float calcDiffuseCoeff( uniform float3 normalW, uniform float3 toLightVecW ) +{ return max( dot( toLightVecW, normalW ), 0.0f ); } + +float calcSpecularCoeff( uniform float3 normalW, uniform float3 toLightVecW, uniform float3 toObserverVecW ) +{ return max( dot( reflect( -toLightVecW, normalW ), toObserverVecW ), 0.0f ); } + +///////////////////////////////////////////////////////////////////// +// SHADOW SAMPLING +///////////////////////////////////////////////////////////////////// +/*SamplerComparisonState shadowSampling +{ + Filter = COMPARISON_MIN_MAG_MIP_POINT; + ComparisonFunc = LESS_EQUAL; + AddressU = BORDER; + AddressV = BORDER; + AddressW = BORDER; + BorderColor = float4( 0.0f, 0.0f, 0.0f, 0.0f ); +};/**/ +/* +SamplerState shadowSampling +{ + Filter = MIN_MAG_MIP_POINT; + AddressU = BORDER; + AddressV = BORDER; + AddressW = BORDER; + BorderColor = float4( 0.0f, 0.0f, 0.0f, 0.0f ); +};/**/ +/* +void sampleShadowPCFx4( uniform float3 posW, uniform Light light, uniform Texture2D shadowMap, uniform float2 shadowMapResolution, out float lightExposure, out float range ) +{ + float4 value = mul( light.worldToLightVolume, float4(posW, 1.0f) ); + value /= value.w; + float2 shadowUV = 0.5f*( float2(value.x, -value.y) + 1.0f ); + float2 shadowUVDelta = 1.0f / shadowMapResolution; + range = value.z - 0.00390625f; + + //lightExposure = shadowMap.SampleCmpLevelZero( shadowSampling, shadowUV, range ).r; + value.x = (float)shadowMap.Sample(shadowSampling, shadowUV ).r; + value.y = (float)shadowMap.Sample(shadowSampling, shadowUV + float2(shadowUVDelta.x, 0.0f) ); + value.z = (float)shadowMap.Sample(shadowSampling, shadowUV + float2(0.0f, shadowUVDelta.y) ); + value.w = (float)shadowMap.Sample(shadowSampling, shadowUV + shadowUVDelta ); + + value.x = range > value.x ? 0.0f : 1.0f; // 1.0f if lightRange is not lesser than range. Else 0.0f + value.y = range > value.y ? 0.0f : 1.0f; + value.z = range > value.z ? 0.0f : 1.0f; + value.w = range > value.w ? 0.0f : 1.0f; + + range += 0.00390625f; + + shadowUV = frac( shadowUV * shadowMapResolution ); + lightExposure = lerp( lerp( value.x, value.y, shadowUV.x ), lerp( value.z, value.w, shadowUV.x ), shadowUV.y ); +} +*/ + +#endif \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/Obj.hlsl b/OysterGraphics/Shader/HLSL/Obj.hlsl new file mode 100644 index 00000000..7e951332 --- /dev/null +++ b/OysterGraphics/Shader/HLSL/Obj.hlsl @@ -0,0 +1,74 @@ +cbuffer Rarely : register(c0) +{ + matrix ViewProjection; +} + +cbuffer everyFrame : register(c1) +{ + matrix View; +} + +cbuffer everyObject : register(c2) +{ + matrix World; +} + +Texture2D Diffuse :register(t0); +Texture2D Specular :register(t1); +Texture2D Glow :register(t2); + +SamplerState LinearSampler : register(s0); + +struct VSObjIn +{ + float3 Pos : POSITION; + float3 Normal : NORMAL; + float2 UV : TEXCOORD; +}; + +struct PSObjIn +{ + float4 Pos : SV_POSITION; + float3 WorldPos : POSITION; + float3 Normal : NORMAL; + float2 UV : TEXCOORD; +}; + +struct PSObjOut +{ + float4 Diffuse : SV_Target0; + float4 Specular : SV_Target1; + float4 Glow : SV_Target2; + float4 Pos : SV_Target3; + float4 Normal : SV_Target4; +}; + +PSObjIn VSObj(VSObjIn input) +{ + PSObjIn output; + matrix WV = mul( World, View ); + matrix WVP = mul (World, ViewProjection ); + output.Pos = mul( float4(input.Pos, 1), WVP ); + output.WorldPos = mul( float4(input.Pos, 1), WV ).xyz; + output.Normal = mul( float4(input.Normal, 0), WV ).xyz; + output.UV = input.UV; + + return output; +} + +float4 PSObj (PSObjIn errors) : SV_Target0 +{ + return Diffuse.Sample( LinearSampler, errors.UV ); +} + +PSObjOut PSDefObj(PSObjIn inp) +{ + PSObjOut outp; + outp.Pos = float4( inp.WorldPos, 1 ); + outp.Normal = float4( normalize(inp.Normal), 0 ); // normalize since interpolation messes them up + outp.Diffuse = Diffuse.Sample( LinearSampler, inp.UV ); + outp.Specular = Specular.Sample( LinearSampler, inp.UV ); + outp.Glow = Glow.Sample( LinearSampler, inp.UV ); + + return outp; +} \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/SSAO.hlsl b/OysterGraphics/Shader/HLSL/SSAO.hlsl new file mode 100644 index 00000000..c255a779 --- /dev/null +++ b/OysterGraphics/Shader/HLSL/SSAO.hlsl @@ -0,0 +1,32 @@ +//Texture2D pos : register(t3); +//Texture2D normal : register(t4); +Texture1D rand : register(t8); +Texture1D sphere : register(t9); + + +float SSAOperPixel( int2 pixel) +{ + float3 rnd = rand[(pixel.x+pixel.y)%rand.Length.x]; + + float3 nvec = normal[pixel].xyz; + float3 tangent = normalize(rnd-nvec * dot(rnd, nvec)); + float3 biTangent = cross(nvec,tangent); + + float3x3 tbn; // = float3x3( nvec, tangent, normal); + tbn[0] =nvec; + tbn[1] =tangent; + tbn[2] =biTangent; + + float occlusion = 0.0f; + for(int i=0;i Quads) +{ + float startoff=input[0].off*input[0].coff; + float endoff=startoff+input[0].coff; + Pixel2DIn output; + + output.Pos = mul(float4(-1,-1,0,1), Translation); + output.Pos.x+=input[0].Pos; + output.Uv = float2(startoff,1); + Quads.Append(output); + + output.Pos = mul(float4(-1,1,0,1), Translation); + output.Pos.x+=input[0].Pos; + output.Uv = float2(startoff,0); + Quads.Append(output); + + output.Pos = mul(float4(1,-1,0,1), Translation); + output.Pos.x+=input[0].Pos; + output.Uv = float2(endoff,1); + Quads.Append(output); + + output.Pos = mul(float4(1,1,0,1), Translation); + output.Pos.x+=input[0].Pos; + output.Uv = float2(endoff,0); + Quads.Append(output); +} \ No newline at end of file diff --git a/OysterGraphics/Shader/HLSL/TileBasedDeffered.hlsl b/OysterGraphics/Shader/HLSL/TileBasedDeffered.hlsl new file mode 100644 index 00000000..6d50eb9c --- /dev/null +++ b/OysterGraphics/Shader/HLSL/TileBasedDeffered.hlsl @@ -0,0 +1,224 @@ +#include "LightMaterialMethods.hlsl" + +#define BLOCKSIZE 16 +#define NUMTHREADS 256 +#define UINT_MAX 0xFFFFFFFF +#define FLOAT_MAX 3.402823466e+38 +#define SSAOSphereRadius 10.0f +#define SPECULARITY_GLOSS_MAX 40.0f + +Texture2D mapMaterialDiffuse : register( t0 ); +Texture2D mapMaterialSpecular : register( t1 ); +Texture2D mapGlow : register( t2 ); +Texture2D mapPosV : register( t3 ); +Texture2D mapNormalV : register( t4 ); +Texture2D mapDepth : register( t5 ); + +StructuredBuffer tileBuffer : register( t6 ); +StructuredBuffer pointLightBuffer : register( t7 ); +Texture1D rand : register( t8 ); +Texture1D sphere : register( t9 ); + +RWTexture2D outputDiffuseIllum : register( u0 ); +RWTexture2D outputSpecularIllum : register( u1 ); +RWTexture2D outputGlowMap : register( u2 ); +RWTexture2D outputSSAOMap : register( u3 ); + +cbuffer LightData : register( c0 ) +{ + float4x4 viewMatrix; + float4x4 projectionMatrix; + uint3 numDispatches; + uint reservedPadding; +}; + +// -- Shared Memory ------------------------------------------------- // + +groupshared uint iMinDepth = UINT_MAX, + iMaxDepth = 0; +groupshared uint numVisiblePointLights = 0, + visiblePointlightIndex[1024]; + +// ------------------------------------------------------------------ // + +[numthreads( BLOCKSIZE, BLOCKSIZE, 1 )] +void lightComputer( uint3 groupID : SV_GroupID, + uint3 groupThreadID : SV_GroupThreadID, + uint groupIndex : SV_GroupIndex, + uint3 dispatchThreadID : SV_DispatchThreadID ) +{ + uint dispatchIndex = dispatchThreadID.x + numDispatches.x * ( dispatchThreadID.y + (numDispatches.y * dispatchThreadID.z) ); + float3 posV = mapPosV[dispatchThreadID.xy].xyz; + + // store and load shared minDepth and maxDepth + float minDepth = 0.0f, maxDepth = 0.0f, + depth = length( posV ); + { + uint uidepth = (uint)( depth * 1024.0f ); + InterlockedMin( iMinDepth, uidepth ); + InterlockedMax( iMaxDepth, uidepth ); + + GroupMemoryBarrierWithGroupSync(); + minDepth = (float)( iMinDepth ) * 0.0009765625f; + maxDepth = (float)( iMaxDepth ) * 0.0009765625f; + } + +// -- Switching to LightCulling ------------------------------------- // + { + Frustrum tile = tileBuffer[dispatchIndex]; + // culling the tile's near and far to minDepth & maxDepth ( with tolerance ) + tile.nearPlane.phasing = -(minDepth * 0.85f); + tile.farPlane.phasing = (maxDepth * 1.15f); + + uint numPointLights = pointLightBuffer.Length.x, + numPass = (numPointLights + NUMTHREADS - 1) / NUMTHREADS; + numPass = min( numPass, 1024 / NUMTHREADS ); + + for( uint passI = 0; passI < numPass; ++passI ) + { + uint lightIndex = (passI * NUMTHREADS) + groupIndex; + lightIndex = min( lightIndex, numPointLights ); + + if( lightIndex < numPointLights ) + if( intersects(tile, pointLightBuffer[lightIndex].pos) ) + { + uint offset; + InterlockedAdd( numVisiblePointLights, 1, offset ); + visiblePointlightIndex[offset] = lightIndex; + } + } + } + GroupMemoryBarrierWithGroupSync(); + + uint2 maxDim = mapMaterialDiffuse.Length.xy; + if( dispatchThreadID.x < maxDim.x && dispatchThreadID.y < maxDim.y ) + { +// -- Switching to per Pixel Light Accumulation --------------------- // + float specularGloss = mapMaterialSpecular[dispatchThreadID.xy].w * SPECULARITY_GLOSS_MAX; + float3 normalV = mapNormalV[dispatchThreadID.xy].xyz; + + float3 diffuseLight = 0, + specularLight = 0; + float4 v = float4( 0.0f, 0.0f, 0.0f, 0.0f ); + + for( uint lightI = 0; lightI < numVisiblePointLights; ++lightI ) + { // for each light that might touch this pixel + uint lightIndex = visiblePointlightIndex[lightI]; + PointLight light = pointLightBuffer[lightIndex]; // should be preloaded into groupshared methinks + + v = mul( viewMatrix, float4(light.pos.center, 1.0f) ); + light.pos.center = v.xyz / v.w; + + v = mul(viewMatrix, float4(light.pos.radius, 0.0f, 0.0f, 0.0f) ); + light.pos.radius = length( v.xyz ); + + float exposure = 1.0f; + + accumulateLight( diffuseLight, specularLight, light, exposure, specularGloss, posV, normalV ); + } + +// -- Applying SSAO ---------------------------------------- Pär H. - // + float occlusion = 0.0f; + { //create sample coordinate system + float4 rnd = float4( rand[groupIndex % rand.Length.x].xyz, 0.0f ); + + + float4 tangent = float4( normalize(rnd.xyz - (normalV * dot(rnd.xyz, normalV))), 0.0f ); + float4 biTangent = float4( cross(tangent.xyz, normalV), 0.0f ); + + float4x4 tbn = float4x4( biTangent, + tangent, + float4(normalV, 0.0f), + float4(posV, 1.0f) ); + + for( uint i = 0; i < sphere.Length.x; ++i ) + { + //take sample from localspace to viewspace + float4 sampled = mul( float4(sphere[i].xyz,1), tbn); + + //project sample to get uv.xy + float4 offset = float4(sampled); + offset = mul( offset, projectionMatrix ); + offset.xy /= offset.w; + offset.xy = offset.xy * 0.5 + 0.5; + offset.y = 1.0f - offset.y; + + // get depth from that point in viewspace + uint2 texCoord; + texCoord.x = (uint)(offset.x * (float)(mapMaterialDiffuse.Length.x)); + texCoord.y = (uint)(offset.y * (float)(mapMaterialDiffuse.Length.y)); + float sampleDepth = length(mapPosV[texCoord]); + float rangeDepth = mapPosV[texCoord].z; + + //compare to depth from sample + float rangeCheck = (abs(depth - sampleDepth) < SSAOSphereRadius) ? 1.0f : 0.0f; + occlusion += (sampleDepth <= length(sampled) ? 1.0f : 0.0f) * rangeCheck; + } + occlusion /= (float)(sphere.Length.x); + occlusion = 1.0f - occlusion; + } + +// -- Compile and write Light values to buffers --------------------- // + + diffuseLight.xyz *= mapMaterialDiffuse[dispatchThreadID.xy].xyz; + specularLight.xyz *= mapMaterialSpecular[dispatchThreadID.xy].xyz; + float4 glow = mapGlow[dispatchThreadID.xy]; + glow *= glow.w; + + //specularLight.xyz += mapGlow[dispatchThreadID.xy].xyz; + + outputDiffuseIllum[dispatchThreadID.xy] = float4( diffuseLight, 1.0f ); + outputSpecularIllum[dispatchThreadID.xy] = float4( specularLight.xyz, 1 ); + outputGlowMap[dispatchThreadID.xy] = float4( glow.xyz * glow.z, 1 ); + outputSSAOMap[dispatchThreadID.xy] = float4( occlusion, occlusion, occlusion, 1 ); + } +} +/* ------------------------------------------------------------------ // + Needs to split into two passes here. As a major Dispatch sync is + is warranted for crossDispatch datasharing. +// ------------------------------------------------------------------ */ + +Texture2D mapDiffuse : register( t0 ); +Texture2D mapSpecular : register( t1 ); +Texture2D Glow : register( t2 ); +Texture2D mapSSAO : register( t3 ); + +RWTexture2D outputBackBuffer : register( u0 ); + +[numthreads( BLOCKSIZE, BLOCKSIZE, 1 )] +void composingComputer( uint3 groupID : SV_GroupID, + uint3 groupThreadID : SV_GroupThreadID, + uint groupIndex : SV_GroupIndex, + uint3 dispatchThreadID : SV_DispatchThreadID ) +{ + uint2 maxDim = mapDiffuse.Length.xy; + if( dispatchThreadID.x < maxDim.x && dispatchThreadID.y < maxDim.y ) + { +// -- Switching to light-material compiling ------------------------- // + float3 diffuse = mapDiffuse[dispatchThreadID.xy].xyz; + float3 specular = mapSpecular[dispatchThreadID.xy].xyz; + float3 glow = Glow[dispatchThreadID.xy].xyz; + float SSAO = mapSSAO[dispatchThreadID.xy].x; + + float3 I = diffuse * SSAO + specular * SSAO + glow * 0.5f; + + //outputBackBuffer[dispatchThreadID.xy] = float4( SSAO,SSAO,SSAO, 1.0f ); + //return; + + uint2 midScreen = mapDiffuse.Length.xy / 2; + if( dispatchThreadID.x < midScreen.x ) + { + if( dispatchThreadID.y < midScreen.y ) + outputBackBuffer[dispatchThreadID.xy] = float4( I, 1.0f ); + else + outputBackBuffer[dispatchThreadID.xy] = float4( diffuse + specular, 1.0f ); + } + else + { + if( dispatchThreadID.y < midScreen.y ) + outputBackBuffer[dispatchThreadID.xy] = float4( glow * 0.5f, 1.0f ); + else + outputBackBuffer[dispatchThreadID.xy] = float4( SSAO, SSAO, SSAO, 1.0f ); + }/**/ + } +} \ No newline at end of file diff --git a/OysterGraphics/Shader/Shader.cpp b/OysterGraphics/Shader/Shader.cpp new file mode 100644 index 00000000..cc939e74 --- /dev/null +++ b/OysterGraphics/Shader/Shader.cpp @@ -0,0 +1,253 @@ +#include "Shader.h" +#include "../Core/Core.h" +#include "Utilities.h" +#include +#include +namespace Oyster +{ + namespace + { + std::vector PS; + std::map PSMap; + + std::vector GS; + std::map GSMap; + + std::vector CS; + std::map CSMap; + + std::vector VS; + std::vector VBlob; + std::map VSMap; + + std::stringstream log; + } + + bool Oyster::Shader::InitShaders(const std::string &name) + { + std::ifstream input; + input.open(name.c_str()); + std::string s, file,method; + std::vector line; + if(!input.is_open()) + return false; + while(!input.eof()) + { + getline(input,s); + line.clear(); + Utility::String::split(line,s,' '); + if(line.size()) + { + if(line[0]=="F") + { + file = line[1]; + } + if(line[0]=="P") + { + ID3D10Blob *Shader,*Error; + if(!PSMap.count(line[2])) + { + PSMap[line[2]]=(int)PS.size(); + ID3D11PixelShader* pixel; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"ps_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + std::string fel = (char*)Error->GetBufferPointer(); + PSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreatePixelShader(Shader->GetBufferPointer(),Shader->GetBufferSize(),NULL,&pixel))) + { + PSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + Shader->Release(); + PS.push_back(pixel); + } + } + if(line[0]=="V") + { + ID3D10Blob *Shader,*Error; + if(!VSMap.count(line[2])) + { + int i = (int)VS.size(); + VSMap[line[2]]= i; + ID3D11VertexShader* vertex; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"vs_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + log //<< "Shader Compilation Warning(s)/Error(s)\n-----------------------------\n" + << (char*) Error->GetBufferPointer(); + // << "-----------------------------\n"; + s = log.str(); + VSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateVertexShader + (Shader->GetBufferPointer(), + Shader->GetBufferSize(), + NULL, + &vertex))) + { + VSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + VS.push_back(vertex); + VBlob.push_back(Shader); + } + } + if(line[0]=="G") + { + ID3D10Blob *Shader,*Error; + if(!GSMap.count(line[2])) + { + GSMap[line[2]]=(int)GS.size(); + ID3D11GeometryShader* pixel; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"gs_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + std::string fel = (char*)Error->GetBufferPointer(); + GSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateGeometryShader(Shader->GetBufferPointer(),Shader->GetBufferSize(),NULL,&pixel))) + { + GSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + Shader->Release(); + GS.push_back(pixel); + } + } + if(line[0]=="C") + { + ID3D10Blob *Shader,*Error; + if(!CSMap.count(line[2])) + { + CSMap[line[2]]=(int)CS.size(); + ID3D11ComputeShader* comp; + if(FAILED(D3DX11CompileFromFileA(file.c_str(),NULL,NULL,line[1].c_str(),"cs_5_0",0,0,NULL,&Shader,&Error,NULL))) + { + std::string fel = (char*)Error->GetBufferPointer(); + CSMap.erase(line[2]); + Error->Release(); + return false; + } + if(FAILED(Oyster::Core::Device->CreateComputeShader(Shader->GetBufferPointer(),Shader->GetBufferSize(),NULL,&comp))) + { + CSMap.erase(line[2]); + Error->Release(); + Shader->Release(); + return false; + } + Shader->Release(); + CS.push_back(comp); + } + } + } + } + return true; + } + + void Oyster::Shader::SetShaderEffect(ShaderEffect se) + { + Shader::Set::SetPixel(se.Shaders.Pixel); + Shader::Set::SetVertex(se.Shaders.Vertex); + Shader::Set::SetGeometry(se.Shaders.Geometry); + Shader::Set::SetCompute(se.Shaders.Compute); + Oyster::Core::DeviceContext->IASetInputLayout(se.IAStage.Layout); + Oyster::Core::DeviceContext->IASetPrimitiveTopology(se.IAStage.Topology); + for(unsigned int i=0;iApply(i); + for(unsigned int i=0;iApply(i); + for(unsigned int i=0;iApply(i); + Oyster::Core::DeviceContext->RSSetState(se.RenderStates.Rasterizer); + Oyster::Core::DeviceContext->PSSetSamplers(0,se.RenderStates.SampleCount,se.RenderStates.SampleState); + float test[4] = {0}; + Oyster::Core::DeviceContext->OMSetBlendState(se.RenderStates.BlendState,test,-1); + } + void Oyster::Shader::Set::SetPixel(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->PSSetShader( NULL,NULL,0); + else + Oyster::Core::DeviceContext->PSSetShader( PS[Index],NULL,0); + } + void Oyster::Shader::Set::SetVertex(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->VSSetShader(NULL,NULL,0); + else + Oyster::Core::DeviceContext->VSSetShader(VS[Index],NULL,0); + } + void Oyster::Shader::Set::SetGeometry(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->GSSetShader(NULL,NULL,0); + else + Oyster::Core::DeviceContext->GSSetShader(GS[Index],NULL,0); + } + void Oyster::Shader::Set::SetCompute(int Index) + { + if(Index==-1) + Oyster::Core::DeviceContext->CSSetShader(NULL,NULL,0); + else + Oyster::Core::DeviceContext->CSSetShader(CS[Index],NULL,0); + } + void Oyster::Shader::Set::SetHull(int Index) + { + } + void Oyster::Shader::Set::SetDomain(int Index) + { + } + + int Oyster::Shader::Get::GetPixel(std::string Name) + { + if(PSMap.count(Name)) + return PSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetVertex(std::string Name) + { + if(VSMap.count(Name)) + return VSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetGeometry(std::string Name) + { + if(GSMap.count(Name)) + return GSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetCompute(std::string Name) + { + if(CSMap.count(Name)) + return CSMap[Name]; + return -1; + } + int Oyster::Shader::Get::GetHull(std::string Name) + { + return -1; + } + int Oyster::Shader::Get::GetDomain(std::string Name) + { + return -1; + } + void Oyster::Shader::CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC *desc, int ElementCount,int VertexIndex,ID3D11InputLayout *&Layout) + { + if(VertexIndex==-1) + { + Layout=0; + return; + } + Oyster::Core::Device->CreateInputLayout(desc,ElementCount,VBlob[VertexIndex]->GetBufferPointer(),VBlob[VertexIndex]->GetBufferSize(),&Layout); + } +} \ No newline at end of file diff --git a/OysterGraphics/Shader/Shader.h b/OysterGraphics/Shader/Shader.h new file mode 100644 index 00000000..957d4314 --- /dev/null +++ b/OysterGraphics/Shader/Shader.h @@ -0,0 +1,78 @@ +#pragma once + +#include "..\Core\Buffer.h" + +namespace Oyster +{ + class Shader + { + public: + struct ShaderEffect + { + struct + { + int Pixel,Vertex,Geometry,Compute,Hull,Domain; + }Shaders; + struct IAStage_ + { + ID3D11InputLayout* Layout; + D3D11_PRIMITIVE_TOPOLOGY Topology; + }IAStage; + struct RenderStates_ + { + ID3D11DepthStencilState *DepthStencil; + ID3D11RasterizerState *Rasterizer; + ID3D11SamplerState **SampleState; + int SampleCount; + ID3D11BlendState *BlendState; + }RenderStates; + struct + { + std::vector Vertex; + std::vector Geometry; + std::vector Pixel; + }CBuffers; + ShaderEffect() + { + RenderStates.BlendState=NULL; + RenderStates.DepthStencil=NULL; + RenderStates.Rasterizer=NULL; + RenderStates.SampleState=NULL; + RenderStates.SampleCount=0; + Shaders.Compute=-1; + Shaders.Domain=-1; + Shaders.Geometry=-1; + Shaders.Hull=-1; + Shaders.Pixel=-1; + Shaders.Vertex=-1; + } + }; + static bool InitShaders(const std::string &name = "..\\Shaders\\ShaderConfig.txt"); + + static void SetShaderEffect(ShaderEffect); + + static void CreateInputLayout(const D3D11_INPUT_ELEMENT_DESC *desc, int ElementCount,int VertexIndex,ID3D11InputLayout *&Layout); + + struct Set + { + static void SetPixel(int Index); + static void SetVertex(int Index); + static void SetGeometry(int Index); + static void SetCompute(int Index); + static void SetHull(int Index); + static void SetDomain(int Index); + }; + + struct Get + { + static int GetPixel(std::string Name); + static int GetVertex(std::string Name); + static int GetGeometry(std::string Name); + static int GetCompute(std::string Name); + static int GetHull(std::string Name); + static int GetDomain(std::string Name); + }; + + static std::stringstream* AccesLog(); + }; +} \ No newline at end of file diff --git a/OysterMath/LinearMath.h b/OysterMath/LinearMath.h new file mode 100644 index 00000000..a9bdef25 --- /dev/null +++ b/OysterMath/LinearMath.h @@ -0,0 +1,268 @@ +///////////////////////////////////////////////////////////////////// +// Collection of Linear Math Stuff +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARMATH_H +#define LINEARMATH_H + +#include "Vector.h" +#include "Matrix.h" +#include "Quaternion.h" +#include + +namespace LinearAlgebra +{ + // x2 + template + Matrix2x2 operator * ( const Matrix2x2 &left, const Matrix2x2 &right ) + { return Matrix2x2( (left.m11 * right.m11) + (left.m21 * right.m12), (left.m11 * right.m21) + (left.m21 * right.m22), (left.m12 * right.m11) + (left.m22 * right.m12), (left.m12 * right.m21) + (left.m22 * right.m22) ); } + + template + Vector2 operator * ( const Matrix2x2 &matrix, const Vector2 &vector ) + { return Vector2( (matrix.m11 * vector.x) + (matrix.m21 * vector.y), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) ); } + + template + Vector2 operator * ( const Vector2 &vector, const Matrix2x2 &left ) + { return Vector2( (vector.x * matrix.m11) + (vector.y * matrix.m12), (vector.x * matrix.m21) + (vector.y * matrix.m22) ); } + + // x3 + template + Matrix3x3 operator * ( const Matrix3x3 &left, const Matrix3x3 &right ) + { + Matrix3x3 product, leftT = left.getTranspose(); + for( int i = 0; i < 3; ++i ) for( int j = 0; j < 3; ++j ) + product.m[i][j] = leftT.v[i].dot(right.v[j]); + return product; + } + + template + Vector3 operator * ( const Matrix3x3 &matrix, const Vector3 &vector ) + { return Vector3( (matrix.m11 * vector.x) + (matrix.m21 * vector.y) + (matrix.m31 * vector.z), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) + (matrix.m32 * vector.z), (matrix.m13 * vector.x) + (matrix.m23 * vector.y) + (matrix.m33 * vector.z) ); } + + template + Vector3 operator * ( const Vector3 &vector, const Matrix3x3 &left ) + { return Vector3( (vector.x * matrix.m11) + (vector.y * matrix.m12) + (vector.z * matrix.m13), (vector.x * matrix.m21) + (vector.y * matrix.m22) + (vector.z * matrix.m23), (vector.x * matrix.m31) + (vector.y * matrix.m32) + (vector.z * matrix.m33) ); } + + // x4 + template + Matrix4x4 operator * ( const Matrix4x4 &left, const Matrix4x4 &right ) + { + Matrix4x4 product, rightT = right.getTranspose(); + for( int i = 0; i < 4; ++i ) + { + product.m[i][0] = left.v[i].dot(rightT.v[0]); + product.m[i][1] = left.v[i].dot(rightT.v[1]); + product.m[i][2] = left.v[i].dot(rightT.v[2]); + product.m[i][3] = left.v[i].dot(rightT.v[3]); + } + return product; + } + + template + Vector4 operator * ( const Matrix4x4 &matrix, const Vector4 &vector ) + { return Vector4( (matrix.m11 * vector.x) + (matrix.m21 * vector.y) + (matrix.m31 * vector.z) + (matrix.m41 * vector.w), (matrix.m12 * vector.x) + (matrix.m22 * vector.y) + (matrix.m32 * vector.z) + (matrix.m42 * vector.w), (matrix.m13 * vector.x) + (matrix.m23 * vector.y) + (matrix.m33 * vector.z) + (matrix.m43 * vector.w), (matrix.m14 * vector.x) + (matrix.m24 * vector.y) + (matrix.m34 * vector.z) + (matrix.m44 * vector.w) ); } + + template // works for column weighted matrixes + Vector4 operator * ( const Vector4 &vector, const Matrix4x4 &matrix ) + { return Vector4( (vector.x * matrix.m11) + (vector.y * matrix.m12) + (vector.z * matrix.m13) + (vector.w * matrix.m14), (vector.x * matrix.m21) + (vector.y * matrix.m22) + (vector.z * matrix.m23) + (vector.w * matrix.m24), (vector.x * matrix.m31) + (vector.y * matrix.m32) + (vector.z * matrix.m33) + (vector.w * matrix.m34), (vector.x * matrix.m41) + (vector.y * matrix.m42) + (vector.z * matrix.m43) + (vector.w * matrix.m44) ); } + + namespace _2D + { + template + inline void translationMatrix( Matrix3x3 &output, const Vector2 &position ) +// { output = Matrix3x3( 1, 0, position.x, 0, 1, position.y, 0, 0, 1 ); } + { output = Matrix3x3( 1, 0, 0, 0, 1, 0, position.x, position.y, 1 ); } + + template + void rotationMatrix( Matrix2x2 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix2x2( c, -s, s, c ); + output = Matrix2x2( c, s, -s, c ); + } + + template + void rotationMatrix( Matrix3x3 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( c, -s, 0, s, c, 0, 0, 0, 1 ); + output = Matrix3x3( c, s, 0, -s, c, 0, 0, 0, 1 ); + } + + template + void rigidBodyMatrix( Matrix3x3 &output, const ElementType &radian, const Vector2 &position ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( c, -s, position.x, s, c, position.y, 0, 0, 1 ); + output = Matrix3x3( c, s, 0, -s, c, 0, position.x, position.y, 1 ); + } + } + + namespace _3D + { + template + inline void translationMatrix( Matrix4x4 &output, const Vector3 &position ) +// { output = Matrix4x4( 1, 0, 0, position.x, 0, 1, 0, position.y, 0, 0, 1, position.z, 0, 0, 0, 1 ); } + { output = Matrix4x4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, position.x, position.y, position.z, 1 ); } + + template + void inverseRigidBody( Matrix4x4 &output, const Matrix4x4 &rigidBody ) + { + output = Matrix4x4( rigidBody.m11, rigidBody.m21, rigidBody.m31, 0, + rigidBody.m12, rigidBody.m22, rigidBody.m32, 0, + rigidBody.m13, rigidBody.m23, rigidBody.m33, 0, + -rigidBody.v[3].xyz.dot(rigidBody.v[0].xyz), + -rigidBody.v[3].xyz.dot(rigidBody.v[1].xyz), + -rigidBody.v[3].xyz.dot(rigidBody.v[2].xyz), 1 ); + } + + template + void rotationMatrix_AxisX( Matrix3x3 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( 1, 0, 0, 0, c, -s, 0, s, c ); + output = Matrix3x3( 1, 0, 0, 0, c, s, 0, -s, c ); + } + + template + void rotationMatrix_AxisX( Matrix4x4 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix4x4( 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1 ); + output = Matrix4x4( 1, 0, 0, 0, 0, c, s, 0, 0, -s, c, 0, 0, 0, 0, 1 ); + } + + template + void rotationMatrix_AxisY( Matrix3x3 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix3x3( c, 0, s, 0, 1, 0, -s, 0, c ); + output = Matrix3x3( c, 0, -s, 0, 1, 0, s, 0, c ); + } + + template + void rotationMatrix_AxisY( Matrix4x4 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix4x4( c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1 ); + output = Matrix4x4( c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, 0, 0, 0, 1 ); + } + + template + inline void rotationMatrix_AxisZ( Matrix3x3 &output, const ElementType &radian ) + { ::LinearAlgebra::_2D::rotationMatrix( output, radian ); } + + template + void rotationMatrix_AxisZ( Matrix4x4 &output, const ElementType &radian ) + { + ElementType s = std::sin( radian ), + c = std::cos( radian ); +// output = Matrix4x4( c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); + output = Matrix4x4( c, s, 0, 0, -s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); + } + + template + void rotationMatrix( Matrix4x4 &output, const Vector3 &normalizedAxis, const ElementType &radian ) + { // TODO : Optimize + ElementType r = radian * 0.5f, + s = std::sin( r ), + c = std::cos( r ); + Quaternion q( normalizedAxis * s, c ), + qConj = q.getConjugate(); + + output.v[0] = Vector4( (q*Vector3(1,0,0)*qConj).imaginary, 0 ); + output.v[1] = Vector4( (q*Vector3(0,1,0)*qConj).imaginary, 0 ); + output.v[2] = Vector4( (q*Vector3(0,0,1)*qConj).imaginary, 0 ); + output.v[3] = Vector4( 0, 0, 0, 1 ); + } + + /* + returns a deltaAngularAxis which is a vectorProduct of the movementVector and leverVector. + angular: (1/I) * L, there I is known as the "moment of inertia", L as the "angular momentum vector". + lever: Displacement vector relative to the rotation pivot. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + template + inline Vector3 deltaAngularAxis( const Vector3 &movement, const Vector3 &lever ) + { return movement.cross( lever ); } + + template + inline Vector3 particleRotationMovement( const Vector3 &deltaRadian, const Vector3 &lever ) + { return lever.cross(deltaRadian) /= lever.dot(lever); } + + template + inline Vector3 vectorProjection( const Vector3 &vector, const Vector3 &axis ) + { return axis * ( vector.dot(axis) / axis.dot(axis) ); } + + /* + output; is set to a rigibody matrix that revolve/rotate around centerOfMass and then translates. + sumDeltaAngularAxis: Sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". + sumTranslation: Sum of all the translation vectors. + centerOfMass: The point the particles is to revolve around, prior to translation. Default set to null vector aka origo. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + template + void rigidBodyMatrix( Matrix4x4 &output, const Vector3 &sumDeltaAngularAxis, const Vector3 &sumTranslation, const Vector3 ¢erOfMass = Vector3::null ) + { + ElementType deltaRadian = sumDeltaAngularAxis.length(); + if( deltaRadian != 0 ) + { + Vector3 axis = sumDeltaAngularAxis / deltaRadian; + rotationMatrix( output, axis, deltaRadian ); + + output.v[3].xyz = centerOfMass; + output.v[3].x -= centerOfMass.dot( output.v[0].xyz ); + output.v[3].y -= centerOfMass.dot( output.v[1].xyz ); + output.v[3].z -= centerOfMass.dot( output.v[2].xyz ); + } + else output = Matrix4x4::identity; + + output.v[3].xyz += sumTranslation; + } + + /* + output; is set to an orthographic projection matrix. + width; of the projection sample volume. + height; of the projection sample volume. + nearClip: Distance to the nearClippingPlane. + farClip: Distance to the farClippingPlane + */ + template + void projectionMatrix_Orthographic( Matrix4x4 &output, const ElementType &width, const ElementType &height, const ElementType &nearClip, const ElementType &farClip ) + { + ElementType c = 1; + c /= nearClip - farClip; + output = Matrix4x4( 2/width, 0, 0, 0, + 0, 2/height, 0, 0, + 0, 0, -c, 0, 0, + 0, nearClip*c, 1 ); + } + + /* + output; is set to a perspective transform matrix. + vertFoV; is the vertical field of vision in radians. (se FoV Hor+ ) + aspect; is the screenratio width/height (example 16/9 or 16/10 ) + nearClip: Distance to the nearClippingPlane + farClip: Distance to the farClippingPlane + */ + template + void projectionMatrix_Perspective( Matrix4x4 &output, const ElementType &vertFoV, const ElementType &aspect, const ElementType &nearClip, const ElementType &farClip ) + { + ElementType fov = 1 / ::std::tan( vertFoV * 0.5f ), + dDepth = farClip; + dDepth /= farClip - nearClip; + output = Matrix4x4( fov / aspect, 0, 0, 0, 0, fov, 0, 0, 0, 0, dDepth, 1, 0, 0, -(dDepth * nearClip), 0 ); + } + } +} + +#endif \ No newline at end of file diff --git a/OysterMath/Matrix.h b/OysterMath/Matrix.h new file mode 100644 index 00000000..ba7b5767 --- /dev/null +++ b/OysterMath/Matrix.h @@ -0,0 +1,761 @@ +///////////////////////////////////////////////////////////////////// +// Linear Math Matrixes +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARALGEBRA_MATRIX_H +#define LINEARALGEBRA_MATRIX_H + +#include "Vector.h" +#include "Utilities.h" + +namespace LinearAlgebra +{ + template + class Matrix2x2 + { + public: + union + { + ElementType m[2][2]; + struct{ Vector2 v[2]; }; +// struct{ ElementType m11, m21, m12, m22; }; + struct{ ElementType m11, m12, m21, m22; }; + ElementType element[4]; + char byte[sizeof(ElementType[4])]; + }; + + static const Matrix2x2 identity, null; + + Matrix2x2( ); + Matrix2x2( const ElementType &m11, const ElementType &m12, + const ElementType &m21, const ElementType &m22 ); + Matrix2x2( const Vector2 vec[2] ); + Matrix2x2( const Vector2 &vec1, const Vector2 &vec2 ); + Matrix2x2( const ElementType element[4] ); + Matrix2x2( const Matrix2x2 &matrix ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + + Matrix2x2 & operator = ( const Vector2 vec[2] ); + Matrix2x2 & operator = ( const ElementType element[4] ); + Matrix2x2 & operator = ( const Matrix2x2 &matrix ); + Matrix2x2 & operator += ( const Matrix2x2 &matrix ); + Matrix2x2 & operator -= ( const Matrix2x2 &matrix ); + Matrix2x2 & operator *= ( const ElementType &scalar ); + Matrix2x2 & operator /= ( const ElementType &scalar ); + Matrix2x2 operator + ( const Matrix2x2 &matrix ) const; + Matrix2x2 operator - ( const Matrix2x2 &matrix ) const; + Matrix2x2 operator * ( const ElementType &scalar ) const; + Matrix2x2 operator / ( const ElementType &scalar ) const; + Matrix2x2 operator - ( ) const; // unary negation + + ElementType getDeterminant( ) const; + Matrix2x2 getAdjoint( ) const; + Matrix2x2 getTranspose( ) const; + Matrix2x2 & transpose( ); + Matrix2x2 getInverse( ) const; + Matrix2x2 getInverse( ElementType &determinant ) const; + Matrix2x2 & invert( ); + Matrix2x2 & invert( ElementType &determinant ); + Vector2 getRowVector( unsigned int rowID ) const; + const Vector2 & getColumnVector( unsigned int colID ) const; + }; + + template + class Matrix3x3 + { + public: + union + { + ElementType m[3][3]; + struct{ Vector3 v[3]; }; +// struct{ ElementType m11, m21, m31, m12, m22, m32, m13, m23, m33; }; + struct{ ElementType m11, m12, m13, m21, m22, m23, m31, m32, m33; }; + ElementType element[9]; + char byte[sizeof(ElementType[9])]; + }; + + static const Matrix3x3 identity, null; + + Matrix3x3( ); + Matrix3x3( const ElementType &m11, const ElementType &m12, const ElementType &m13, + const ElementType &m21, const ElementType &m22, const ElementType &m23, + const ElementType &m31, const ElementType &m32, const ElementType &m33 ); + Matrix3x3( const Vector3 vec[3] ); + Matrix3x3( const Vector3 &vec1, const Vector3 &vec2, const Vector3 &vec3 ); + Matrix3x3( const ElementType element[9] ); + Matrix3x3( const Matrix3x3 &matrix ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + + Matrix3x3 & operator = ( const Vector3 vec[3] ); + Matrix3x3 & operator = ( const ElementType element[9] ); + Matrix3x3 & operator = ( const Matrix3x3 &matrix ); + Matrix3x3 & operator += ( const Matrix3x3 &matrix ); + Matrix3x3 & operator -= ( const Matrix3x3 &matrix ); + Matrix3x3 & operator *= ( const ElementType &scalar ); + Matrix3x3 & operator /= ( const ElementType &scalar ); + Matrix3x3 operator + ( const Matrix3x3 &matrix ) const; + Matrix3x3 operator - ( const Matrix3x3 &matrix ) const; + Matrix3x3 operator * ( const ElementType &scalar ) const; + Matrix3x3 operator / ( const ElementType &scalar ) const; + Matrix3x3 operator - ( ) const; // unary negation + + ElementType getDeterminant( ) const; + Matrix3x3 getAdjoint( ) const; + Matrix3x3 getTranspose( ) const; + Matrix3x3 & transpose( ); + Matrix3x3 getInverse( ) const; + Matrix3x3 getInverse( ElementType &determinant ) const; + Matrix3x3 & invert( ); + Matrix3x3 & invert( ElementType &determinant ); + Vector3 getRowVector( unsigned int rowID ) const; + const Vector3 & getColumnVector( unsigned int colID ) const; + }; + + template + class Matrix4x4 + { + public: + union + { + ElementType m[4][4]; + struct{ Vector4 v[4]; }; +// struct{ ElementType m11, m21, m31, m41, m12, m22, m32, m42, m13, m23, m33, m43, m14, m24, m34, m44; }; + struct{ ElementType m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44; }; + ElementType element[16]; + char byte[sizeof(ElementType[16])]; + }; + + static const Matrix4x4 identity, null; + + Matrix4x4( ); + Matrix4x4( const ElementType &m11, const ElementType &m12, const ElementType &m13, const ElementType &m14, + const ElementType &m21, const ElementType &m22, const ElementType &m23, const ElementType &m24, + const ElementType &m31, const ElementType &m32, const ElementType &m33, const ElementType &m34, + const ElementType &m41, const ElementType &m42, const ElementType &m43, const ElementType &m44 ); + Matrix4x4( const Vector4 vec[4] ); + Matrix4x4( const Vector4 &vec1, const Vector4 &vec2, const Vector4 &vec3, const Vector4 &vec4 ); + Matrix4x4( const ElementType element[16] ); + Matrix4x4( const Matrix4x4 &matrix ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + + Matrix4x4 & operator = ( const Vector4 vec[4] ); + Matrix4x4 & operator = ( const ElementType element[16] ); + Matrix4x4 & operator = ( const Matrix4x4 &matrix ); + Matrix4x4 & operator += ( const Matrix4x4 &matrix ); + Matrix4x4 & operator -= ( const Matrix4x4 &matrix ); + Matrix4x4 & operator *= ( const ElementType &scalar ); + Matrix4x4 & operator /= ( const ElementType &scalar ); + Matrix4x4 operator + ( const Matrix4x4 &matrix ) const; + Matrix4x4 operator - ( const Matrix4x4 &matrix ) const; + Matrix4x4 operator * ( const ElementType &scalar ) const; + Matrix4x4 operator / ( const ElementType &scalar ) const; + Matrix4x4 operator - ( ) const; // unary negation + + ElementType getDeterminant( ) const; + Matrix4x4 getAdjoint( ) const; + Matrix4x4 getTranspose( ) const; + Matrix4x4 & transpose( ); + Matrix4x4 getInverse( ) const; + Matrix4x4 getInverse( ElementType &determinant ) const; + Matrix4x4 & invert( ); + Matrix4x4 & invert( ElementType &determinant ); + Vector4 getRowVector( unsigned int rowID ) const; + const Vector4 & getColumnVector( unsigned int colID ) const; + }; + +/////////////////////////////////////////////////////////////////////////////////// +// Body +/////////////////////////////////////////////////////////////////////////////////// + +// Matrix2x2 /////////////////////////////////////// + template + const Matrix2x2 Matrix2x2::identity = Matrix2x2( 1, 0, 0, 1 ); + + template + const Matrix2x2 Matrix2x2::null = Matrix2x2( 0, 0, 0, 0 ); + + template + Matrix2x2::Matrix2x2( ) : m11(0), m21(0), m12(0), m22(0) {} + + template + Matrix2x2::Matrix2x2( const ElementType &_m11, const ElementType &_m12, const ElementType &_m21, const ElementType &_m22 ) + : m11(_m11), m21(_m21), m12(_m12), m22(_m22) {} + + template + Matrix2x2::Matrix2x2( const Vector2 vec[2] ) + : m11(vec[0].x), m21(vec[0].y), m12(vec[1].x), m22(vec[1].y) {} + + template + Matrix2x2::Matrix2x2( const Vector2 &vec1, const Vector2 &vec2 ) + : m11(vec1.x), m21(vec1.y), m12(vec2.x), m22(vec2.y) {} + + template + Matrix2x2::Matrix2x2( const ElementType _element[4] ) +// : m11(_element[0]), m21(_element[1]), m12(_element[2]), m22(_element[3]) {} + : m11(_element[0]), m12(_element[1]), m21(_element[2]), m22(_element[3]) {} + + template + Matrix2x2::Matrix2x2( const Matrix2x2 &matrix ) + : m11(matrix.m11), m21(matrix.m12), m12(matrix.m21), m22(matrix.m22) {} + + template + inline Matrix2x2::operator ElementType* ( ) + { return this->element; } + + template + inline Matrix2x2::operator const ElementType* ( ) const + { return this->element; } + + template + Matrix2x2 & Matrix2x2::operator = ( const Vector2 vec[2] ) + { + this->v[0] = vec[0]; + this->v[1] = vec[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator = ( const ElementType element[4] ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator = ( const Matrix2x2 &matrix ) + { + this->v[0] = matrix.v[0]; + this->v[1] = matrix.v[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator += ( const Matrix2x2 &matrix ) + { + this->v[0] += matrix.v[0]; + this->v[1] += matrix.v[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator -= ( const Matrix2x2 &matrix ) + { + this->v[0] -= matrix.v[0]; + this->v[1] -= matrix.v[1]; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator *= ( const ElementType &scalar ) + { + this->v[0] *= scalar; + this->v[1] *= scalar; + return *this; + } + + template + Matrix2x2 & Matrix2x2::operator /= ( const ElementType &scalar ) + { + this->v[0] /= scalar; + this->v[1] /= scalar; + return *this; + } + + template + inline Matrix2x2 Matrix2x2::operator + ( const Matrix2x2 &matrix ) const + { return Matrix2x2(*this) += matrix; } + + template + inline Matrix2x2 Matrix2x2::operator - ( const Matrix2x2 &matrix ) const + { return Matrix2x2(*this) -= matrix; } + + template + inline Matrix2x2 Matrix2x2::operator * ( const ElementType &scalar ) const + { return Matrix2x2(*this) *= scalar; } + + template + inline Matrix2x2 Matrix2x2::operator / ( const ElementType &scalar ) const + { return Matrix2x2(*this) /= scalar; } + + template + inline Matrix2x2 Matrix2x2::operator - ( ) const + { return Matrix2x2(-this->v[0], -this->v[1]); } + + template + ElementType Matrix2x2::getDeterminant( ) const + { + ElementType determinant = (this->m11 * this->m22); + return determinant -= (this->m12 * this->m21); + } + + template + Matrix2x2 Matrix2x2::getAdjoint( ) const + { return Matrix2x2( this->m22, -this->m21, -this->m12, this->m11 ); } + + template + inline Matrix2x2 Matrix2x2::getTranspose( ) const + { return Matrix2x2( this->element[0], this->element[1], this->element[2], this->element[3] ); } + + template + Matrix2x2 & Matrix2x2::transpose( ) + { + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + return *this; + } + + template + inline Matrix2x2 Matrix2x2::getInverse( ) const + { return this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix2x2 Matrix2x2::getInverse( ElementType &determinant ) const + { + determinant = this->getDeterminant(); + if( determinant != 0 ) + return this->getAdjoint() / determinant; + return Matrix2x2(); + } + + template + Matrix2x2 & Matrix2x2::invert( ) + { + *this /= this->getDeterminant(); + this->m12 *= -1; this->m21 *= -1; + + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + Utility::Element::swap( this->m11, this->m22, swapSpace ); + return *this; + } + + template + Matrix2x2 & Matrix2x2::invert( ElementType &determinant ) + { + determinant = this->getDeterminant(); + + if( determinant != 0 ) + { + *this /= determinant; + this->m12 *= -1; this->m21 *= -1; + + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + Utility::Element::swap( this->m11, this->m22, swapSpace ); + } + return *this; + } + + template + inline Vector2 Matrix2x2::getRowVector( unsigned int rowID ) const + { return Vector2( this->m[0][rowID], this->m[1][rowID] ); } + + template + inline const Vector2 & Matrix2x2::getColumnVector( unsigned int colID ) const + { return this->v[colID]; } + +// Matrix3x3 /////////////////////////////////////// + template + const Matrix3x3 Matrix3x3::identity = Matrix3x3( 1, 0, 0, 0, 1, 0, 0, 0, 1 ); + + template + const Matrix3x3 Matrix3x3::null = Matrix3x3( 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + template + Matrix3x3::Matrix3x3( ) : m11(0), m21(0), m31(0), m12(0), m22(0), m32(0), m13(0), m23(0), m33(0) {} + + template + Matrix3x3::Matrix3x3( const ElementType &_m11, const ElementType &_m12, const ElementType &_m13, const ElementType &_m21, const ElementType &_m22, const ElementType &_m23, const ElementType &_m31, const ElementType &_m32, const ElementType &_m33 ) + : m11(_m11), m21(_m21), m31(_m31), m12(_m12), m22(_m22), m32(_m32), m13(_m13), m23(_m23), m33(_m33) {} + + template + Matrix3x3::Matrix3x3( const Vector3 vec[3] ) + : m11(vec[0].x), m21(vec[0].y), m31(vec[0].z), m12(vec[1].x), m22(vec[1].y), m32(vec[1].z), m13(vec[2].x), m23(vec[2].y), m33(vec[2].z) {} + + template + Matrix3x3::Matrix3x3( const Vector3 &vec1, const Vector3 &vec2, const Vector3 &vec3 ) + : m11(vec1.x), m21(vec1.y), m31(vec1.z), m12(vec2.x), m22(vec2.y), m32(vec2.z), m13(vec3.x), m23(vec3.y), m33(vec3.z) {} + + template + Matrix3x3::Matrix3x3( const ElementType _element[9] ) +// : m11(_element[0]), m21(_element[1]), m31(_element[2]), m12(_element[3]), m22(_element[4]), m32(_element[5]), m13(_element[6]), m23(_element[7]), m33(_element[8]) {} + : m11(_element[0]), m12(_element[1]), m13(_element[2]), m21(_element[3]), m22(_element[4]), m23(_element[5]), m31(_element[6]), m32(_element[7]), m33(_element[8]) {} + + template + Matrix3x3::Matrix3x3( const Matrix3x3 &matrix ) + : m11(matrix.m11), m21(matrix.m21), m31(matrix.m31), m12(matrix.m12), m22(matrix.m22), m32(matrix.m32), m13(matrix.m13), m23(matrix.m23), m33(matrix.m33) {} + + template + inline Matrix3x3::operator ElementType* ( ) + { return this->element; } + + template + inline Matrix3x3::operator const ElementType* ( ) const + { return this->element; } + + template + Matrix3x3 & Matrix3x3::operator = ( const Vector3 vec[3] ) + { + this->v[0] = vec[0]; + this->v[1] = vec[1]; + this->v[2] = vec[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator = ( const ElementType element[9] ) + { + for( int i = 0; i < 9; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator = ( const Matrix3x3 &matrix ) + { + this->v[0] = matrix.v[0]; + this->v[1] = matrix.v[1]; + this->v[2] = matrix.v[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator += ( const Matrix3x3 &matrix ) + { + this->v[0] += matrix.v[0]; + this->v[1] += matrix.v[1]; + this->v[2] += matrix.v[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator -= ( const Matrix3x3 &matrix ) + { + this->v[0] -= matrix.v[0]; + this->v[1] -= matrix.v[1]; + this->v[2] -= matrix.v[2]; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator *= ( const ElementType &scalar ) + { + this->v[0] *= scalar; + this->v[1] *= scalar; + this->v[2] *= scalar; + return *this; + } + + template + Matrix3x3 & Matrix3x3::operator /= ( const ElementType &scalar ) + { + this->v[0] /= scalar; + this->v[1] /= scalar; + this->v[2] /= scalar; + return *this; + } + + template + inline Matrix3x3 Matrix3x3::operator + ( const Matrix3x3 &matrix ) const + { return Matrix3x3(*this) += matrix; } + + template + inline Matrix3x3 Matrix3x3::operator - ( const Matrix3x3 &matrix ) const + { return Matrix3x3(*this) -= matrix; } + + template + inline Matrix3x3 Matrix3x3::operator * ( const ElementType &scalar ) const + { return Matrix3x3(*this) *= scalar; } + + template + inline Matrix3x3 Matrix3x3::operator / ( const ElementType &scalar ) const + { return Matrix3x3(*this) /= scalar; } + + template + inline Matrix3x3 Matrix3x3::operator - ( ) const + { return Matrix3x3(-this->v[0], -this->v[1], -this->v[2]); } + + template + ElementType Matrix3x3::getDeterminant( ) const + { + ElementType determinant = (this->m11 * this->m22 * this->m33); + determinant += (this->m12 * this->m23 * this->m31); + determinant += (this->m13 * this->m21 * this->m32); + determinant -= (this->m11 * this->m23 * this->m32); + determinant -= (this->m12 * this->m21 * this->m33); + return determinant -= (this->m13 * this->m22 * this->m31); + } + + template + Matrix3x3 Matrix3x3::getAdjoint( ) const + { + return Matrix3x3( (this->m22*this->m33 - this->m23*this->m32), (this->m13*this->m32 - this->m12*this->m33), (this->m12*this->m23 - this->m13*this->m22), + (this->m23*this->m31 - this->m21*this->m33), (this->m11*this->m33 - this->m13*this->m31), (this->m13*this->m21 - this->m11*this->m23), + (this->m21*this->m32 - this->m22*this->m31), (this->m12*this->m31 - this->m11*this->m32), (this->m11*this->m22 - this->m12*this->m21) ); + } + + template + inline Matrix3x3 Matrix3x3::getTranspose( ) const + { + return Matrix3x3( this->m11, this->m21, this->m31, + this->m12, this->m22, this->m32, + this->m13, this->m23, this->m33 ); + } + + template + Matrix3x3 & Matrix3x3::transpose( ) + { + ElementType swapSpace; + Utility::Element::swap( this->m12, this->m21, swapSpace ); + Utility::Element::swap( this->m13, this->m31, swapSpace ); + Utility::Element::swap( this->m23, this->m32, swapSpace ); + return *this; + } + + template + Matrix3x3 Matrix3x3::getInverse( ) const + { return this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix3x3 Matrix3x3::getInverse( ElementType &determinant ) const + { + determinant = this->getDeterminant(); + if( determinant != 0 ) + return this->getAdjoint() /= determinant; + else return Matrix3x3(); + } + + template + Matrix3x3 & Matrix3x3::invert( ) + { return *this = this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix3x3 & Matrix3x3::invert( ElementType &determinant ) + { + determinant = this->getDeterminant(); + if( determinant != 0 ) + return *this = this->getAdjoint() /= determinant; + return *this; + } + + template + inline Vector3 Matrix3x3::getRowVector( unsigned int rowID ) const + { return Vector3( this->m[0][rowID], this->m[1][rowID], this->m[2][rowID] ); } + + template + inline const Vector3 & Matrix3x3::getColumnVector( unsigned int colID ) const + { return this->v[colID]; } + +// Matrix4x4 /////////////////////////////////////// + template + const Matrix4x4 Matrix4x4::identity = Matrix4x4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); + + template + const Matrix4x4 Matrix4x4::null = Matrix4x4( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + + template + Matrix4x4::Matrix4x4( ) + : m11(0), m21(0), m31(0), m41(0), m12(0), m22(0), m32(0), m42(0), m13(0), m23(0), m33(0), m43(0), m14(0), m24(0), m34(0), m44(0) {} + + template + Matrix4x4::Matrix4x4( const ElementType &_m11, const ElementType &_m12, const ElementType &_m13, const ElementType &_m14, const ElementType &_m21, const ElementType &_m22, const ElementType &_m23, const ElementType &_m24, const ElementType &_m31, const ElementType &_m32, const ElementType &_m33, const ElementType &_m34, const ElementType &_m41, const ElementType &_m42, const ElementType &_m43, const ElementType &_m44 ) + : m11(_m11), m21(_m21), m31(_m31), m41(_m41), m12(_m12), m22(_m22), m32(_m32), m42(_m42), m13(_m13), m23(_m23), m33(_m33), m43(_m43), m14(_m14), m24(_m24), m34(_m34), m44(_m44) {} + + template + Matrix4x4::Matrix4x4( const Vector4 vec[4] ) + : m11(vec[0].x), m21(vec[0].y), m31(vec[0].z), m41(vec[0].w), m12(vec[1].x), m22(vec[1].y), m32(vec[1].z), m42(vec[1].w), m13(vec[2].x), m23(vec[2].y), m33(vec[2].z), m43(vec[2].w), m14(vec[3].x), m24(vec[3].y), m34(vec[3].z), m44(vec[3].w) {} + + template + Matrix4x4::Matrix4x4( const Vector4 &vec1, const Vector4 &vec2, const Vector4 &vec3, const Vector4 &vec4 ) + : m11(vec1.x), m21(vec1.y), m31(vec1.z), m41(vec1.w), m12(vec2.x), m22(vec2.y), m32(vec2.z), m42(vec2.w), m13(vec3.x), m23(vec3.y), m33(vec3.z), m43(vec3.w), m14(vec4.x), m24(vec4.y), m34(vec4.z), m44(vec4.w) {} + + template + Matrix4x4::Matrix4x4( const ElementType _element[16] ) +// : m11(_element[0]), m21(_element[1]), m31(_element[2]), m41(_element[3]), m12(_element[4]), m22(_element[5]), m32(_element[6]), m42(_element[7]), m13(_element[8]), m23(_element[9]), m33(_element[10]), m43(_element[11]), m14(_element[12]), m24(_element[13]), m34(_element[14]), m44(_element[15]) {} + : m11(_element[0]), m12(_element[1]), m13(_element[2]), m14(_element[3]), m21(_element[4]), m22(_element[5]), m23(_element[6]), m24(_element[7]), m31(_element[8]), m32(_element[9]), m33(_element[10]), m34(_element[11]), m41(_element[12]), m42(_element[13]), m43(_element[14]), m44(_element[15]) {} + + template + Matrix4x4::Matrix4x4( const Matrix4x4 &matrix ) + : m11(matrix.m11), m21(matrix.m21), m31(matrix.m31), m41(matrix.m41), m12(matrix.m12), m22(matrix.m22), m32(matrix.m32), m42(matrix.m42), m13(matrix.m13), m23(matrix.m23), m33(matrix.m33), m43(matrix.m43), m14(matrix.m14), m24(matrix.m24), m34(matrix.m34), m44(matrix.m44) {} + + template + inline Matrix4x4::operator ElementType* ( ) + { return this->element; } + + template + inline Matrix4x4::operator const ElementType* ( ) const + { return this->element; } + + template + Matrix4x4 & Matrix4x4::operator = ( const Vector4 vec[4] ) + { + this->v[0] = vec[0]; + this->v[1] = vec[1]; + this->v[2] = vec[2]; + this->v[3] = vec[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator = ( const ElementType element[16] ) + { + for( int i = 0; i < 16; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator = ( const Matrix4x4 &matrix ) + { + this->v[0] = matrix.v[0]; + this->v[1] = matrix.v[1]; + this->v[2] = matrix.v[2]; + this->v[3] = matrix.v[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator += ( const Matrix4x4 &matrix ) + { + this->v[0] += matrix.v[0]; + this->v[1] += matrix.v[1]; + this->v[2] += matrix.v[2]; + this->v[3] += matrix.v[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator -= ( const Matrix4x4 &matrix ) + { + this->v[0] -= matrix.v[0]; + this->v[1] -= matrix.v[1]; + this->v[2] -= matrix.v[2]; + this->v[3] -= matrix.v[3]; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator *= ( const ElementType &scalar ) + { + this->v[0] *= scalar; + this->v[1] *= scalar; + this->v[2] *= scalar; + this->v[3] *= scalar; + return *this; + } + + template + Matrix4x4 & Matrix4x4::operator /= ( const ElementType &scalar ) + { + this->v[0] /= scalar; + this->v[1] /= scalar; + this->v[2] /= scalar; + this->v[3] /= scalar; + return *this; + } + + template + inline Matrix4x4 Matrix4x4::operator + ( const Matrix4x4 &matrix ) const + { return Matrix4x4(*this) += matrix; } + + template + inline Matrix4x4 Matrix4x4::operator - ( const Matrix4x4 &matrix ) const + { return Matrix4x4(*this) -= matrix; } + + template + inline Matrix4x4 Matrix4x4::operator * ( const ElementType &scalar ) const + { return Matrix4x4(*this) *= scalar; } + + template + inline Matrix4x4 Matrix4x4::operator / ( const ElementType &scalar ) const + { return Matrix4x4(*this) /= scalar; } + + template + inline Matrix4x4 Matrix4x4::operator - ( ) const + { return Matrix4x4(-this->v[0], -this->v[1], -this->v[2], -this->v[3]); } + + template + ElementType Matrix4x4::getDeterminant( ) const + { + ElementType determinant = this->m11 * Matrix3x3(this->m22, this->m23, this->m24, this->m32, this->m33, this->m34, this->m42, this->m43, this->m44).getDeterminant(); + determinant -= this->m12 * Matrix3x3(this->m21, this->m23, this->m24, this->m31, this->m33, this->m34, this->m41, this->m43, this->m44).getDeterminant(); + determinant += this->m13 * Matrix3x3(this->m21, this->m22, this->m24, this->m31, this->m32, this->m34, this->m41, this->m42, this->m44).getDeterminant(); + return determinant -= this->m14 * Matrix3x3(this->m21, this->m22, this->m23, this->m31, this->m32, this->m33, this->m41, this->m42, this->m43).getDeterminant(); + } + + template + Matrix4x4 Matrix4x4::getAdjoint( ) const + { + return Matrix4x4( Matrix3x3(this->m22, this->m23, this->m24, this->m32, this->m33, this->m34, this->m42, this->m43, this->m44).getDeterminant(), -Matrix3x3(this->m12, this->m13, this->m14, this->m32, this->m33, this->m34, this->m42, this->m43, this->m44).getDeterminant(), Matrix3x3(this->m12, this->m13, this->m14, this->m22, this->m23, this->m24, this->m42, this->m43, this->m44).getDeterminant(), -Matrix3x3(this->m12, this->m13, this->m14, this->m22, this->m23, this->m24, this->m32, this->m33, this->m34).getDeterminant(), + -Matrix3x3(this->m21, this->m23, this->m24, this->m31, this->m33, this->m34, this->m41, this->m43, this->m44).getDeterminant(), Matrix3x3(this->m11, this->m13, this->m14, this->m31, this->m33, this->m34, this->m41, this->m43, this->m44).getDeterminant(), -Matrix3x3(this->m11, this->m13, this->m14, this->m21, this->m23, this->m24, this->m41, this->m43, this->m44).getDeterminant(), Matrix3x3(this->m11, this->m13, this->m14, this->m21, this->m23, this->m24, this->m31, this->m33, this->m34).getDeterminant(), + Matrix3x3(this->m21, this->m22, this->m24, this->m31, this->m32, this->m34, this->m41, this->m42, this->m44).getDeterminant(), -Matrix3x3(this->m11, this->m12, this->m14, this->m31, this->m32, this->m34, this->m41, this->m42, this->m44).getDeterminant(), Matrix3x3(this->m11, this->m12, this->m14, this->m21, this->m22, this->m24, this->m41, this->m42, this->m44).getDeterminant(), -Matrix3x3(this->m11, this->m12, this->m14, this->m21, this->m22, this->m24, this->m31, this->m32, this->m34).getDeterminant(), + -Matrix3x3(this->m21, this->m22, this->m23, this->m31, this->m32, this->m33, this->m41, this->m42, this->m43).getDeterminant(), Matrix3x3(this->m11, this->m12, this->m13, this->m31, this->m32, this->m33, this->m41, this->m42, this->m43).getDeterminant(), -Matrix3x3(this->m11, this->m12, this->m13, this->m21, this->m22, this->m23, this->m41, this->m42, this->m43).getDeterminant(), Matrix3x3(this->m11, this->m12, this->m13, this->m21, this->m22, this->m23, this->m31, this->m32, this->m33).getDeterminant() ); + } + + template + inline Matrix4x4 Matrix4x4::getTranspose( ) const + { + return Matrix4x4( this->m11, this->m21, this->m31, this->m41, + this->m12, this->m22, this->m32, this->m42, + this->m13, this->m23, this->m33, this->m43, + this->m14, this->m24, this->m34, this->m44 ); + } + + template + Matrix4x4 & Matrix4x4::transpose( ) + { + ElementType swapSpace; + ::Utility::Element::swap( this->m12, this->m21, swapSpace ); + ::Utility::Element::swap( this->m13, this->m31, swapSpace ); + ::Utility::Element::swap( this->m14, this->m41, swapSpace ); + ::Utility::Element::swap( this->m23, this->m32, swapSpace ); + ::Utility::Element::swap( this->m24, this->m42, swapSpace ); + ::Utility::Element::swap( this->m34, this->m43, swapSpace ); + return *this; + } + + template + inline Matrix4x4 Matrix4x4::getInverse( ) const + { return this->getAdjoint() /= this->getDeterminant() ; } + + template + Matrix4x4 Matrix4x4::getInverse( ElementType &determinant ) const + { + determinant = this->getDeterminant(); + if( determinant != 0.0f ) + return this->getAdjoint() /= determinant; + return Matrix4x4(); + } + + template + Matrix4x4 & Matrix4x4::invert( ) + { return *this = this->getAdjoint() /= this->getDeterminant(); } + + template + Matrix4x4 & Matrix4x4::invert( ElementType &determinant ) + { + determinant = this->getDeterminant(); + if( determinant != 0.0f ) + return *this = this->getAdjoint() /= determinant; + return *this; + } + + template + inline Vector4 Matrix4x4::getRowVector( unsigned int rowID ) const + { return Vector4( this->m[0][rowID], this->m[1][rowID], this->m[2][rowID], this->m[3][rowID] ); } + + template + inline const Vector4 & Matrix4x4::getColumnVector( unsigned int colID ) const + { return this->v[colID]; } +} + +#endif \ No newline at end of file diff --git a/OysterMath/OysterMath.cpp b/OysterMath/OysterMath.cpp new file mode 100644 index 00000000..43ec9cde --- /dev/null +++ b/OysterMath/OysterMath.cpp @@ -0,0 +1,32 @@ +///////////////////////////////////////////////////////////////////// +// by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "OysterMath.h" + +namespace Oyster { namespace Math +{ + Float2 & operator *= ( Float2 &left, const Float2 &right ) + { + left.x *= right.x; + left.y *= right.y; + return left; + } + + Float3 & operator *= ( Float3 &left, const Float3 &right ) + { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + return left; + } + + Float4 & operator *= ( Float4 &left, const Float4 &right ) + { + left.x *= right.x; + left.y *= right.y; + left.z *= right.z; + left.w *= right.w; + return left; + } +} } \ No newline at end of file diff --git a/OysterMath/OysterMath.h b/OysterMath/OysterMath.h new file mode 100644 index 00000000..821312fc --- /dev/null +++ b/OysterMath/OysterMath.h @@ -0,0 +1,220 @@ +///////////////////////////////////////////////////////////////////// +// by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_MATH_H +#define OYSTER_MATH_H + +#include "Utilities.h" +#include "LinearMath.h" +#include + +namespace Oyster { namespace Math +{ + typedef float Float; + + typedef ::LinearAlgebra::Vector2 Float2; + typedef ::LinearAlgebra::Vector3 Float3; + typedef ::LinearAlgebra::Vector4 Float4; + + typedef ::LinearAlgebra::Matrix2x2 Float2x2; + typedef ::LinearAlgebra::Matrix3x3 Float3x3; + typedef ::LinearAlgebra::Matrix4x4 Float4x4; + + typedef Float4x4 Matrix; + typedef Float2 Vector2; + typedef Float3 Vector3; + typedef Float4 Vector4; + + + + Float2 & operator *= ( Float2 &left, const Float2 &right ); + + inline Float2 operator * ( const Float2 &left, const Float2 &right ) + { return Float2(left) *= right; } + + inline Float2 operator * ( const Float &left, const Float2 &right ) + { return Float2(right) *= left; } + + Float3 & operator *= ( Float3 &left, const Float3 &right ); + + inline Float3 operator * ( const Float3 &left, const Float3 &right ) + { return Float3(left) *= right; } + + inline Float3 operator * ( const Float &left, const Float3 &right ) + { return Float3(right) *= left; } + + Float4 & operator *= ( Float4 &left, const Float4 &right ); + + inline Float4 operator * ( const Float4 &left, const Float4 &right ) + { return Float4(left) *= right; } + + inline Float4 operator * ( const Float &left, const Float4 &right ) + { return Float4(right) *= left; } + + inline Float2x2 operator * ( const Float &left, const Float2x2 &right ) + { return Float2x2(right) *= left; } + + inline Float3x3 operator * ( const Float &left, const Float3x3 &right ) + { return Float3x3(right) *= left; } + + inline Float4x4 operator * ( const Float &left, const Float4x4 &right ) + { return Float4x4(right) *= left; } + + // Deprecated function! Use the static const member identity instead. + inline void identityMatrix( Float2x2 &output ) + { output = Float2x2::identity; } + + // Deprecated function! Use the static const member identity instead. + inline void identityMatrix( Float3x3 &output ) + { output = Float3x3::identity; } + + // Deprecated function! Use the static const member identity instead. + inline void identityMatrix( Float4x4 &output ) + { output = Float4x4::identity; } + + // If rigidBody is assumed to be by all definitions a rigid body matrix. Then this is a faster inverse method. + inline void inverseRigidBodyMatrix( Float4x4 &output, const Float4x4 &rigidBody ) + { ::LinearAlgebra::_3D::inverseRigidBody( output, rigidBody ); } + + inline void translationMatrix( Float4x4 &output, const Float3 &position ) + { ::LinearAlgebra::_3D::translationMatrix( output, position ); } + + // counterclockwise rotation around X axis + inline void rotationMatrix_AxisX( Float4x4 &output, const Float &radian ) + { ::LinearAlgebra::_3D::rotationMatrix_AxisX( output, radian ); } + + // counterclockwise rotation around Y axis + inline void rotationMatrix_AxisY( Float4x4 &output, const Float &radian ) + { ::LinearAlgebra::_3D::rotationMatrix_AxisY( output, radian ); } + + // counterclockwise rotation around Z axis + inline void rotationMatrix_AxisZ( Float4x4 &output, const Float &radian ) + { ::LinearAlgebra::_3D::rotationMatrix_AxisZ( output, radian ); } + + // counterclockwise rotation around any given Float3 vector (normalizedAxis). Please make sure it is normalized. + inline void rotationMatrix( Float4x4 &output, const Float &radian, const Float3 &normalizedAxis ) + { ::LinearAlgebra::_3D::rotationMatrix( output, normalizedAxis, radian ); } + + /* + returns a deltaAngularAxis which is a vectorProduct of the particleMovementVector and leverVector. + angular: (1/I) * L, there I is known as the "moment of inertia", L as the "angular momentum vector". + lever: Displacement vector relative to the center of mass. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + inline Float3 deltaAngularAxis( const Float3 &movement, const Float3 &lever ) + { return ::LinearAlgebra::_3D::deltaAngularAxis( movement, lever ); } + + inline Float3 particleRotationMovement( const Float3 &deltaRadian, const Float3 &lever ) + { return ::LinearAlgebra::_3D::particleRotationMovement( deltaRadian, lever ); } + + inline Float3 vectorProjection( const Float3 &vector, const Float3 &axis ) + { return ::LinearAlgebra::_3D::vectorProjection( vector, axis ); } + + /* + output: is set to a rigibody matrix that revolve/rotate around centerOfMass and then translates. + sumDeltaAngularAxis: sum of all ( (1/I) * ( L x D ) )-vectorproducts. There I is known as "moment of inertia", L as "angular momentum vector" and D the "lever vector". + sumTranslation: sum of all the translation vectors. + centerOfMass: the point the particles is to revolve around, prior to translation. Default set to null vector aka origo. + Recommended reading: http://en.wikipedia.org/wiki/Torque + */ + inline void rigidBodyMatrix( Float4x4 &output, const Float3 &sumDeltaAngularAxis, const Float3 &sumTranslation, const Float3 ¢erOfMass = Float3::null ) + { ::LinearAlgebra::_3D::rigidBodyMatrix( output, sumDeltaAngularAxis, sumTranslation, centerOfMass ); } + + /* + output; is set to an orthographic projection matrix. + width; of the projection sample volume. + height; of the projection sample volume. + near: Distance to the nearPlane. + far: Distance to the farPlane + */ + inline void projectionMatrix_Orthographic( Float4x4 &output, const Float &width, const Float &height, const Float &nearClip = ::std::numeric_limits::epsilon(), const Float &farClip = ::std::numeric_limits::max() ) + { ::LinearAlgebra::_3D::projectionMatrix_Orthographic( output, width, height, nearClip, farClip ); } + + /* + output; is set to a perspective transform matrix. + vertFoV; is the vertical field of vision in radians. (se FoV Hor+ ) + aspect; is the screenratio width/height (example 16/9 or 16/10 ) + near: Distance to the nearPlane + far: Distance to the farPlane + */ + inline void projectionMatrix_Perspective( Float4x4 &output, const Float &verticalFoV, const Float &aspectRatio, const Float &nearClip = ::std::numeric_limits::epsilon(), const Float &farClip = ::std::numeric_limits::max() ) + { ::LinearAlgebra::_3D::projectionMatrix_Perspective( output, verticalFoV, aspectRatio, nearClip, farClip ); } + + inline Float4x4 & viewProjectionMatrix( Float4x4 &output, const Float4x4 &view, const Float4x4 &projection ) + { return output = (view * projection).getTranspose(); } + + inline Float4x4 & transformMatrix( Float4x4 &output, const Float4x4 &transformee, const Float4x4 &transformer ) + { return output = transformee * transformer; } + + inline Float4x4 transformMatrix( const Float4x4 &transformee, const Float4x4 &transformer ) + { return transformee * transformer; } + + inline Float4 & transformVector( Float4 &output, const Float4 &transformee, const Float4x4 &transformer ) + { return output = transformer * transformee; } + + inline Float4 transformVector( const Float4 &transformee, const Float4x4 &transformer ) + { return transformee * transformer; } +} } + +namespace Utility { namespace Value +{ // Utility Value Specializations + using namespace ::Oyster::Math; + + template< > inline Float2 abs( const Float2 &value ) + { return Float2( abs(value.x), abs(value.y) ); } + + template< > inline Float2 max( const Float2 &valueA, const Float2 &valueB ) + { return Float2( max(valueA.x, valueB.x), max(valueA.y, valueB.y) ); } + + template< > inline Float2 min( const Float2 &valueA, const Float2 &valueB ) + { return Float2( min(valueA.x, valueB.x), min(valueA.y, valueB.y) ); } + + template< > inline Float3 abs( const Float3 &value ) + { return Float3( abs(value.xy), abs(value.z) ); } + + template< > inline Float3 max( const Float3 &valueA, const Float3 &valueB ) + { return Float3( max(valueA.xy, valueB.xy), max(valueA.z, valueB.z) ); } + + template< > inline Float3 min( const Float3 &valueA, const Float3 &valueB ) + { return Float3( min(valueA.xy, valueB.xy), min(valueA.z, valueB.z) ); } + + template< > inline Float4 abs( const Float4 &value ) + { return Float4( abs(value.xyz), abs(value.w) ); } + + template< > inline Float4 max( const Float4 &valueA, const Float4 &valueB ) + { return Float4( max(valueA.xyz, valueB.xyz), max(valueA.w, valueB.w) ); } + + template< > inline Float4 min( const Float4 &valueA, const Float4 &valueB ) + { return Float4( min(valueA.xyz, valueB.xyz), min(valueA.w, valueB.w) ); } + + template< > inline Float2x2 abs( const Float2x2 &value ) + { return Float2x2( abs(value.v[0]), abs(value.v[1]) ); } + + template< > inline Float2x2 max( const Float2x2 &valueA, const Float2x2 &valueB ) + { return Float2x2( max(valueA.v[0], valueB.v[0]), max(valueA.v[1], valueB.v[1]) ); } + + template< > inline Float2x2 min( const Float2x2 &valueA, const Float2x2 &valueB ) + { return Float2x2( min(valueA.v[0], valueB.v[0]), min(valueA.v[1], valueB.v[1]) ); } + + template< > inline Float3x3 abs( const Float3x3 &value ) + { return Float3x3( abs(value.v[0]), abs(value.v[1]), abs(value[2]) ); } + + template< > inline Float3x3 max( const Float3x3 &valueA, const Float3x3 &valueB ) + { return Float3x3( max(valueA.v[0], valueB.v[0]), max(valueA.v[1], valueB.v[1]), max(valueA.v[2], valueB.v[2]) ); } + + template< > inline Float3x3 min( const Float3x3 &valueA, const Float3x3 &valueB ) + { return Float3x3( min(valueA.v[0], valueB.v[0]), min(valueA.v[1], valueB.v[1]), min(valueA.v[2], valueB.v[2]) ); } + + template< > inline Float4x4 abs( const Float4x4 &value ) + { return Float4x4( abs(value.v[0]), abs(value.v[1]), abs(value[2]), abs(value[3]) ); } + + template< > inline Float4x4 max( const Float4x4 &valueA, const Float4x4 &valueB ) + { return Float4x4( max(valueA.v[0], valueB.v[0]), max(valueA.v[1], valueB.v[1]), max(valueA.v[2], valueB.v[2]), max(valueA.v[3], valueB.v[3]) ); } + + template< > inline Float4x4 min( const Float4x4 &valueA, const Float4x4 &valueB ) + { return Float4x4( min(valueA.v[0], valueB.v[0]), min(valueA.v[1], valueB.v[1]), min(valueA.v[2], valueB.v[2]), min(valueA.v[3], valueB.v[3]) ); } +} } + +#endif \ No newline at end of file diff --git a/OysterMath/Quaternion.h b/OysterMath/Quaternion.h new file mode 100644 index 00000000..383c0245 --- /dev/null +++ b/OysterMath/Quaternion.h @@ -0,0 +1,183 @@ +///////////////////////////////////////////////////////////////////// +// Linear Math Quaternions +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARALGEBRA_QUATERNION_H +#define LINEARALGEBRA_QUATERNION_H + +#include "Vector.h" +#include + +namespace LinearAlgebra +{ + template + class Quaternion + { + public: + union + { + struct{ Vector3 imaginary; ElementType real; }; + ElementType element[4]; + char byte[sizeof(ElementType[2])]; + }; + + Quaternion( ); + Quaternion( const Quaternion &quaternion ); + Quaternion( const Vector3 &imaginary, const ElementType &real ); + ~Quaternion( ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Quaternion & operator = ( const Quaternion &quaternion ); + Quaternion & operator *= ( const ElementType &scalar ); + Quaternion & operator /= ( const ElementType &scalar ); + Quaternion & operator += ( const Quaternion &quaternion ); + Quaternion & operator -= ( const Quaternion &quaternion ); + Quaternion operator * ( const Quaternion &quaternion ) const; + Quaternion operator * ( const Vector3 &vector ) const; + Quaternion operator * ( const ElementType &scalar ) const; + Quaternion operator / ( const ElementType &scalar ) const; + Quaternion operator + ( const Quaternion &quaternion ) const; + Quaternion operator - ( const Quaternion &quaternion ) const; + Quaternion operator - ( ) const; + + Quaternion getConjugate( ) const; + }; + +/////////////////////////////////////////////////////////////////////////////////// +// Body +/////////////////////////////////////////////////////////////////////////////////// + + template + Quaternion::Quaternion( ) : imaginary(0,0,0), real(0) {} + + template + Quaternion::Quaternion( const Quaternion &quaternion ) : imaginary(quaternion.imaginary), real(quaternion.real) {} + + template + Quaternion::Quaternion( const Vector3 &_imaginary, const ElementType &_real ) : imaginary(_imaginary), real(_real) {} + + template + Quaternion::~Quaternion( ) { /* Nothing that needs to be done */ } + + template + inline Quaternion::operator ElementType* ( ) + { return this->element; } + + template + inline Quaternion::operator const ElementType* ( ) const + { return this->element; } + + template + inline Quaternion::operator char* ( ) + { return this->byte; } + + template + inline Quaternion::operator const char* ( ) const + { return this->byte; } + + template + inline ElementType & Quaternion::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Quaternion::operator [] ( int i ) const + { return this->element[i]; } + + template + Quaternion & Quaternion::operator = ( const Quaternion &quaternion ) + { + this->imaginary = quaternion.imaginary; + this->real = quaternion.real; + return *this; + } + + template + Quaternion & Quaternion::operator *= ( const ElementType &scalar ) + { + this->imaginary *= scalar; + this->real *= scalar; + return *this; + } + + template + Quaternion & Quaternion::operator /= ( const ElementType &scalar ) + { + this->imaginary /= scalar; + this->real /= scalar; + return *this; + } + + template + Quaternion & Quaternion::operator += ( const Quaternion &quaternion ) + { + this->imaginary += quaternion.imaginary; + this->real += quaternion.real; + return *this; + } + + template + Quaternion & Quaternion::operator -= ( const Quaternion &quaternion ) + { + this->imaginary -= quaternion.imaginary; + this->real -= quaternion.real; + return *this; + } + + template + Quaternion Quaternion::operator * ( const Quaternion &quaternion ) const + { + Vector3 im = this->imaginary.cross( quaternion.imaginary ); + im += (quaternion.imaginary * this->real); + im += (this->imaginary * quaternion.real); + + ElementType re = this->real * quaternion.real; + re -= this->imaginary.dot( quaternion.imaginary ); + + return Quaternion( im, re ); + } + + template + Quaternion Quaternion::operator * ( const Vector3 &vector ) const + { + Vector3 im = this->imaginary.cross( vector ); + im += (vector * this->real); + + ElementType re = this->imaginary.dot( vector ) * -1; + + return Quaternion( im, re ); + } + + template + inline Quaternion Quaternion::operator * ( const ElementType &scalar ) const + { return Quaternion(*this) *= scalar; } + + template + inline Quaternion Quaternion::operator / ( const ElementType &scalar ) const + { return Quaternion(*this) /= scalar; } + + template + inline Quaternion Quaternion::operator + ( const Quaternion &quaternion ) const + { return Quaternion(*this) += quaternion; } + + template + inline Quaternion Quaternion::operator - ( const Quaternion &quaternion ) const + { return Quaternion(*this) -= quaternion; } + + template + inline Quaternion Quaternion::operator - ( ) const + { return Quaternion(-this->imaginary, -this->real); } + + template + inline Quaternion Quaternion::getConjugate( ) const + { return Quaternion(this->imaginary * -1, this->real ); } +} + +#endif \ No newline at end of file diff --git a/OysterMath/Vector.h b/OysterMath/Vector.h new file mode 100644 index 00000000..086ed7d8 --- /dev/null +++ b/OysterMath/Vector.h @@ -0,0 +1,659 @@ +///////////////////////////////////////////////////////////////////// +// Linear Math Vectors +// © Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef LINEARALGEBRA_VECTOR_H +#define LINEARALGEBRA_VECTOR_H + +#include + +namespace LinearAlgebra +{ + template + class Vector2 + { + public: + union + { + struct { ElementType x, y; }; + ElementType element[2]; + char byte[sizeof(ElementType[2])]; + }; + + static const Vector2 null; + static const Vector2 standardUnitX; + static const Vector2 standardUnitY; + + Vector2( ); + Vector2( const Vector2 &vector ); + Vector2( const ElementType &element ); + Vector2( const ElementType element[2] ); + Vector2( const ElementType &x, const ElementType &y ); + ~Vector2( ); + + operator ElementType* ( ); + operator const ElementType* ( ) const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Vector2 & operator = ( const Vector2 &vector ); + Vector2 & operator = ( const ElementType element[2] ); + Vector2 & operator *= ( const ElementType &scalar ); + Vector2 & operator /= ( const ElementType &scalar ); + Vector2 & operator += ( const Vector2 &vector ); + Vector2 & operator -= ( const Vector2 &vector ); + Vector2 operator * ( const ElementType &scalar ) const; + Vector2 operator / ( const ElementType &scalar ) const; + Vector2 operator + ( const Vector2 &vector ) const; + Vector2 operator - ( const Vector2 &vector ) const; + Vector2 operator - ( ) const; // unary negation + + bool operator == ( const Vector2 &vector ) const; + bool operator != ( const Vector2 &vector ) const; + + ElementType length( ) const; + ElementType dot( const Vector2 &vector ) const; + + Vector2 & normalize( ); + Vector2 getNormalized( ) const; + }; + + template + class Vector3 + { + public: + union + { + struct { ElementType x, y, z; }; + struct { Vector2 xy; }; + ElementType element[3]; + char byte[sizeof(ElementType[3])]; + }; + + static const Vector3 null; + static const Vector3 standardUnitX; + static const Vector3 standardUnitY; + static const Vector3 standardUnitZ; + + Vector3( ); + Vector3( const Vector3 &vector ); + Vector3( const Vector2 &vector, const ElementType &z ); + Vector3( const ElementType &element ); + Vector3( const ElementType element[3] ); + Vector3( const ElementType &x, const ElementType &y, const ElementType &z ); + ~Vector3( ); + + operator ElementType* (); + operator const ElementType* () const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Vector3 & operator = ( const Vector3 &vector ); + Vector3 & operator = ( const ElementType element[3] ); + Vector3 & operator *= ( const ElementType &scalar ); + Vector3 & operator /= ( const ElementType &scalar ); + Vector3 & operator += ( const Vector3 &vector ); + Vector3 & operator -= ( const Vector3 &vector ); + Vector3 operator * ( const ElementType &scalar ) const; + Vector3 operator / ( const ElementType &scalar ) const; + Vector3 operator + ( const Vector3 &vector ) const; + Vector3 operator - ( const Vector3 &vector ) const; + Vector3 operator - ( ) const; // unary negation + + bool operator == ( const Vector3 &vector ) const; + bool operator != ( const Vector3 &vector ) const; + + ElementType length( ) const; + ElementType dot( const Vector3 &vector ) const; + Vector3 cross( const Vector3 &vector ) const; + + Vector3 & normalize( ); + Vector3 getNormalized( ) const; + }; + + template + class Vector4 + { + public: + union + { + struct { ElementType x, y, z, w; }; + struct { Vector2 xy; }; + struct { Vector3 xyz; }; + ElementType element[4]; + char byte[sizeof(ElementType[4])]; + }; + + static const Vector4 null; + static const Vector4 standardUnitX; + static const Vector4 standardUnitY; + static const Vector4 standardUnitZ; + static const Vector4 standardUnitW; + + Vector4( ); + Vector4( const Vector4 &vector ); + Vector4( const Vector3 &vector, const ElementType &w ); + Vector4( const Vector2 &vector, const ElementType &z, const ElementType &w ); + Vector4( const ElementType &element ); + Vector4( const ElementType element[4] ); + Vector4( const ElementType &x, const ElementType &y, const ElementType &z, const ElementType &w ); + ~Vector4( ); + + operator ElementType* (); + operator const ElementType* () const; + operator char* ( ); + operator const char* ( ) const; + ElementType & operator [] ( int i ); + const ElementType & operator [] ( int i ) const; + + Vector4 & operator = ( const Vector4 &vector ); + Vector4 & operator = ( const ElementType element[4] ); + Vector4 & operator *= ( const ElementType &scalar ); + Vector4 & operator /= ( const ElementType &scalar ); + Vector4 & operator += ( const Vector4 &vector ); + Vector4 & operator -= ( const Vector4 &vector ); + Vector4 operator * ( const ElementType &scalar ) const; + Vector4 operator / ( const ElementType &scalar ) const; + Vector4 operator + ( const Vector4 &vector ) const; + Vector4 operator - ( const Vector4 &vector ) const; + Vector4 operator - ( ) const; // unary negation + + bool operator == ( const Vector4 &vector ) const; + bool operator != ( const Vector4 &vector ) const; + + ElementType length( ) const; + ElementType dot( const Vector4 &vector ) const; + + Vector4 & normalize( ); + Vector4 getNormalized( ) const; + }; + +/////////////////////////////////////////////////////////////////////////////////// +// Body +/////////////////////////////////////////////////////////////////////////////////// + +// Vector2 /////////////////////////////////////// + template const Vector2 Vector2::null = Vector2( ); + template const Vector2 Vector2::standardUnitX = Vector2( 1, 0 ); + template const Vector2 Vector2::standardUnitY = Vector2( 0, 1 ); + + template + Vector2::Vector2( ) : x(0), y(0) {} + + template + Vector2::Vector2( const Vector2 &vector ) : x(vector.x), y(vector.y) + { this->x = vector.x; this->y = vector.y; } + + template + Vector2::Vector2( const ElementType &_element ) : x(_element), y(_element) + { this->x = this->y = _element; } + + template + Vector2::Vector2( const ElementType _element[2] ) : x(_element[0]), y(_element[1]) {} + + template + Vector2::Vector2( const ElementType &_x, const ElementType &_y ) : x(_x), y(_y) {} + + template + Vector2::~Vector2( ) { /* Nothing that needs to be done */ } + + template + inline Vector2::operator ElementType* () + { return this->element; } + + template + inline Vector2::operator const ElementType* () const + { return this->element; } + + template + inline Vector2::operator char* ( ) + { return this->byte; } + + template + inline Vector2::operator const char* ( ) const + { return this->byte; } + + template + inline ElementType & Vector2::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Vector2::operator [] ( int i ) const + { return this->element[i]; } + + template + Vector2 & Vector2::operator = ( const Vector2 &vector ) + { + this->element[0] = vector.element[0]; + this->element[1] = vector.element[1]; + return *this; + } + + template + Vector2 & Vector2::operator = ( const ElementType _element[2] ) + { + this->element[0] = _element[0]; + this->element[1] = _element[1]; + return *this; + } + + template + Vector2 & Vector2::operator *= ( const ElementType &scalar ) + { + this->element[0] *= scalar; + this->element[1] *= scalar; + return *this; + } + + template + Vector2 & Vector2::operator /= ( const ElementType &scalar ) + { + this->element[0] /= scalar; + this->element[1] /= scalar; + return *this; + } + + template + Vector2 & Vector2::operator += ( const Vector2 &vector ) + { + this->element[0] += vector.element[0]; + this->element[1] += vector.element[1]; + return *this; + } + + template + Vector2 & Vector2::operator -= ( const Vector2 &vector ) + { + this->element[0] -= vector.element[0]; + this->element[1] -= vector.element[1]; + return *this; + } + + template + inline Vector2 Vector2::operator * ( const ElementType &scalar ) const + { return Vector2(*this) *= scalar; } + + template + inline Vector2 Vector2::operator / ( const ElementType &scalar ) const + { return Vector2(*this) /= scalar; } + + template + inline Vector2 Vector2::operator + ( const Vector2 &vector ) const + { return Vector2(*this) += vector; } + + template + inline Vector2 Vector2::operator - ( const Vector2 &vector ) const + { return Vector2(*this) -= vector; } + + template + inline Vector2 Vector2::operator - ( ) const + { return Vector2(-this->x, -this->y); } + + template + bool Vector2::operator == ( const Vector2 &vector ) const + { + if( this->x != vector.x ) return false; + if( this->y != vector.y ) return false; + return true; + } + + template + bool Vector2::operator != ( const Vector2 &vector ) const + { + if( this->x != vector.x ) return true; + if( this->y != vector.y ) return true; + return false; + } + + template + inline ElementType Vector2::length( ) const + { return (ElementType) ::sqrt( this->dot(*this) ); } + + template + ElementType Vector2::dot( const Vector2 &vector ) const + { + ElementType value = 0; + value += this->element[0] * vector.element[0]; + value += this->element[1] * vector.element[1]; + return value; + } + + template + inline Vector2 & Vector2::normalize( ) + { return (*this) /= this->length(); } + + template + inline Vector2 Vector2::getNormalized( ) const + { return Vector2(*this).normalize(); } + +// Vector3 /////////////////////////////////////// + template const Vector3 Vector3::null = Vector3( ); + template const Vector3 Vector3::standardUnitX = Vector3( 1, 0, 0 ); + template const Vector3 Vector3::standardUnitY = Vector3( 0, 1, 0 ); + template const Vector3 Vector3::standardUnitZ = Vector3( 0, 0, 1 ); + + template + Vector3::Vector3( ) : x(0), y(0), z(0) {} + + template + Vector3::Vector3( const Vector3 &vector ) : x(vector.x), y(vector.y), z(vector.z) + { this->x = vector.x; this->y = vector.y; this->z = vector.z; } + + template + Vector3::Vector3( const Vector2 &vector, const ElementType &_z ) : x(vector.x), y(vector.y), z(_z) + { this->x = vector.x; this->y = vector.y; } + + template + Vector3::Vector3( const ElementType &_element ) : x(_element), y(_element), z(_element) + { this->x = this->y = this->z = _element; } + + template + Vector3::Vector3( const ElementType _element[3] ) : x(_element[0]), y(_element[1]), z(_element[2]) {} + + template + Vector3::Vector3( const ElementType &_x, const ElementType &_y, const ElementType &_z ) : x(_x), y(_y), z(_z) + { this->x = _x; this->y = _y; this->z = _z; } + + template + Vector3::~Vector3( ) { /* Nothing that needs to be done */ } + + template + inline Vector3::operator ElementType* () + { return this->element; } + + template + inline Vector3::operator const ElementType* () const + { return this->element; } + + template + inline ElementType & Vector3::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Vector3::operator [] ( int i ) const + { return this->element[i]; } + + template + Vector3 & Vector3::operator = ( const Vector3 &vector ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] = vector.element[i]; + return *this; + } + + template + Vector3 & Vector3::operator = ( const ElementType element[3] ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Vector3 & Vector3::operator *= ( const ElementType &scalar ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] *= scalar; + return *this; + } + + template + Vector3 & Vector3::operator /= ( const ElementType &scalar ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] /= scalar; + return *this; + } + + template + Vector3 & Vector3::operator += ( const Vector3 &vector ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] += vector.element[i]; + return *this; + } + + template + Vector3 & Vector3::operator -= ( const Vector3 &vector ) + { + for( int i = 0; i < 3; ++i ) + this->element[i] -= vector.element[i]; + return *this; + } + + template + inline Vector3 Vector3::operator * ( const ElementType &scalar ) const + { return Vector3(*this) *= scalar; } + + template + inline Vector3 Vector3::operator / ( const ElementType &scalar ) const + { return Vector3(*this) /= scalar; } + + template + inline Vector3 Vector3::operator + ( const Vector3 &vector ) const + { return Vector3(*this) += vector; } + + template + inline Vector3 Vector3::operator - ( const Vector3 &vector ) const + { return Vector3(*this) -= vector; } + + template + inline Vector3 Vector3::operator - ( ) const + { return Vector3(-this->x, -this->y, -this->z); } + + template + bool Vector3::operator == ( const Vector3 &vector ) const + { + if( this->x != vector.x ) return false; + if( this->y != vector.y ) return false; + if( this->z != vector.z ) return false; + return true; + } + + template + bool Vector3::operator != ( const Vector3 &vector ) const + { + if( this->x != vector.x ) return true; + if( this->y != vector.y ) return true; + if( this->z != vector.z ) return true; + return false; + } + + template + inline ElementType Vector3::length( ) const + { return (ElementType) ::sqrt( this->dot(*this) ); } + + template + ElementType Vector3::dot( const Vector3 &vector ) const + { + ElementType value = 0; + for( int i = 0; i < 3; ++i ) + value += this->element[i] * vector.element[i]; + return value; + } + + template + Vector3 Vector3::cross( const Vector3 &vector ) const + { + return Vector3( (this->y*vector.z) - (this->z*vector.y), + (this->z*vector.x) - (this->x*vector.z), + (this->x*vector.y) - (this->y*vector.x) ); + } + + template + inline Vector3 & Vector3::normalize( ) + { return (*this) /= this->length(); } + + template + inline Vector3 Vector3::getNormalized( ) const + { return Vector3(*this).normalize(); } + +// Vector4 /////////////////////////////////////// + template const Vector4 Vector4::null = Vector4( ); + template const Vector4 Vector4::standardUnitX = Vector4( 1, 0, 0, 0 ); + template const Vector4 Vector4::standardUnitY = Vector4( 0, 1, 0, 0 ); + template const Vector4 Vector4::standardUnitZ = Vector4( 0, 0, 1, 0 ); + template const Vector4 Vector4::standardUnitW = Vector4( 0, 0, 0, 1 ); + + template + Vector4::Vector4( ) : x(0), y(0), z(0), w(0) {} + + template + Vector4::Vector4( const Vector4 &vector ) : x(vector.x), y(vector.y), z(vector.z), w(vector.z) + { this->x = vector.x; this->y = vector.y; this->z = vector.z; this->w = vector.w; } + + template + Vector4::Vector4( const Vector3 &vector, const ElementType &_w ) : x(vector.x), y(vector.y), z(vector.z), w(_w) + { this->x = vector.x; this->y = vector.y; this->z = vector.z; } + + template + Vector4::Vector4( const Vector2 &vector, const ElementType &_z, const ElementType &_w ) : x(vector.x), y(vector.y), z(_z), w(_w) + { this->x = vector.x; this->y = vector.y; this->z = _z; this->w = _w; } + + template + Vector4::Vector4( const ElementType &_element ) : x(_element), y(_element), z(_element), w(_element) + { this->x = this->y = this->z = this->w = _element; } + + template + Vector4::Vector4( const ElementType _element[4] ) : x(_element[0]), y(_element[1]), z(_element[2]), w(_element[3]) {} + + template + Vector4::Vector4( const ElementType &_x, const ElementType &_y, const ElementType &_z, const ElementType &_w ) : x(_x), y(_y), z(_z), w(_w) + { this->x = _x; this->y = _y; this->z = _z; this->w = _w; } + + template + Vector4::~Vector4( ) { /* Nothing that needs to be done */ } + + template + inline Vector4::operator ElementType* () + { return this->element; } + + template + inline Vector4::operator const ElementType* () const + { return this->element; } + + template + inline ElementType & Vector4::operator [] ( int i ) + { return this->element[i]; } + + template + inline const ElementType & Vector4::operator [] ( int i ) const + { return this->element[i]; } + + template + Vector4 & Vector4::operator = ( const Vector4 &vector ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] = vector.element[i]; + return *this; + } + + template + Vector4 & Vector4::operator = ( const ElementType element[4] ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] = element[i]; + return *this; + } + + template + Vector4 & Vector4::operator *= ( const ElementType &scalar ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] *= scalar; + return *this; + } + + template + Vector4 & Vector4::operator /= ( const ElementType &scalar ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] /= scalar; + return *this; + } + + template + Vector4 & Vector4::operator += ( const Vector4 &vector ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] += vector.element[i]; + return *this; + } + + template + Vector4 & Vector4::operator -= ( const Vector4 &vector ) + { + for( int i = 0; i < 4; ++i ) + this->element[i] -= vector.element[i]; + return *this; + } + + template + inline Vector4 Vector4::operator * ( const ElementType &scalar ) const + { return Vector4(*this) *= scalar; } + + template + inline Vector4 Vector4::operator / ( const ElementType &scalar ) const + { return Vector4(*this) /= scalar; } + + template + inline Vector4 Vector4::operator + ( const Vector4 &vector ) const + { return Vector4(*this) += vector; } + + template + inline Vector4 Vector4::operator - ( const Vector4 &vector ) const + { return Vector4(*this) -= vector; } + + template + inline Vector4 Vector4::operator - ( ) const + { return Vector4(-this->x, -this->y, -this->z, -this->w); } + + template + bool Vector4::operator == ( const Vector4 &vector ) const + { + if( this->x != vector.x ) return false; + if( this->y != vector.y ) return false; + if( this->z != vector.z ) return false; + if( this->w != vector.w ) return false; + return true; + } + + template + bool Vector4::operator != ( const Vector4 &vector ) const + { + if( this->x != vector.x ) return true; + if( this->y != vector.y ) return true; + if( this->z != vector.z ) return true; + if( this->w != vector.w ) return true; + return false; + } + + template + inline ElementType Vector4::length( ) const + { return (ElementType) ::sqrt( this->dot(*this) ); } + + template + ElementType Vector4::dot( const Vector4 &vector ) const + { + ElementType value = 0; + for( int i = 0; i < 4; ++i ) + value += this->element[i] * vector.element[i]; + return value; + } + + template + inline Vector4 & Vector4::normalize( ) + { return (*this) /= this->length(); } + + template + inline Vector4 Vector4::getNormalized( ) const + { return Vector4(*this).normalize(); } +} + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Box.cpp b/OysterPhysics3D/Collision/Box.cpp new file mode 100644 index 00000000..3c1b416e --- /dev/null +++ b/OysterPhysics3D/Collision/Box.cpp @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Box.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Box::Box( ) : ICollideable(ICollideable::Box), orientation(Float4x4::identity), boundingOffset() {} + +Box::Box( const Box &box ) : ICollideable(ICollideable::Box), orientation(box.orientation), boundingOffset(box.boundingOffset) +{ + this->orientation = box.orientation; +} + +Box::Box( const Float4x4 &o, const Float3 &s ) : ICollideable(ICollideable::Box), orientation(o), boundingOffset(s*0.5) +{ + this->orientation = o; +} +Box::~Box( ) { /*Nothing needs to be done here*/ } + +Box & Box::operator = ( const Box &box ) +{ + this->orientation = box.orientation; + this->boundingOffset = box.boundingOffset; + return *this; +} + +ICollideable* Box::clone( ) const +{ return new Box( *this ); } + +bool Box::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target ); + case ICollideable::Box: return Utility::intersect( *this, *(Collision::Box*)target ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Box::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Sphere: return false; // TODO + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +ICollideable::State Box::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Box.h b/OysterPhysics3D/Collision/Box.h new file mode 100644 index 00000000..8e60b875 --- /dev/null +++ b/OysterPhysics3D/Collision/Box.h @@ -0,0 +1,44 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_BOX_H +#define OYSTER_COLLISION_BOX_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Box : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float4x4 orientation; ::Oyster::Math::Float3 boundingOffset; }; + struct + { + ::Oyster::Math::Float3 xAxis; ::Oyster::Math::Float paddingA; + ::Oyster::Math::Float3 yAxis; ::Oyster::Math::Float paddingB; + ::Oyster::Math::Float3 zAxis; ::Oyster::Math::Float paddingC; + ::Oyster::Math::Float3 center; + }; + char byte[sizeof(::Oyster::Math::Float4x4) + sizeof(::Oyster::Math::Float3)]; + }; + + Box( ); + Box( const Box &box ); + Box( const ::Oyster::Math::Float4x4 &orientation, const ::Oyster::Math::Float3 &size ); + ~Box( ); + + Box & operator = ( const Box &box ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/BoxAxisAligned.cpp b/OysterPhysics3D/Collision/BoxAxisAligned.cpp new file mode 100644 index 00000000..42630656 --- /dev/null +++ b/OysterPhysics3D/Collision/BoxAxisAligned.cpp @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "BoxAxisAligned.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +BoxAxisAligned::BoxAxisAligned( ) : ICollideable(ICollideable::BoxAxisAligned), minVertex(-0.5f,-0.5f,-0.5f), maxVertex(0.5f,0.5f,0.5f) {} +BoxAxisAligned::BoxAxisAligned( const BoxAxisAligned &box ) : ICollideable(ICollideable::BoxAxisAligned), minVertex(box.minVertex), maxVertex(box.maxVertex) {} +BoxAxisAligned::BoxAxisAligned( const Float3 &_minVertex, const Float3 &_maxVertex ) : ICollideable(ICollideable::BoxAxisAligned), minVertex(_minVertex), maxVertex(_maxVertex) {} +BoxAxisAligned::BoxAxisAligned( const Float &leftClip, const Float &rightClip, const Float &topClip, const Float &bottomClip, const Float &nearClip, const Float &farClip ) + : ICollideable(ICollideable::BoxAxisAligned), minVertex(leftClip, bottomClip, nearClip), maxVertex(rightClip, topClip, farClip) {} +BoxAxisAligned::~BoxAxisAligned( ) { /*Nothing needs to be done here*/ } + +BoxAxisAligned & BoxAxisAligned::operator = ( const BoxAxisAligned &box ) +{ + this->minVertex = box.minVertex; + this->maxVertex = box.maxVertex; + return *this; +} + +ICollideable* BoxAxisAligned::clone( ) const +{ return new BoxAxisAligned( *this ); } + +bool BoxAxisAligned::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target ); + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool BoxAxisAligned::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return false; // TODO + case ICollideable::Sphere: return false; // TODO + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +ICollideable::State BoxAxisAligned::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/BoxAxisAligned.h b/OysterPhysics3D/Collision/BoxAxisAligned.h new file mode 100644 index 00000000..712f75fb --- /dev/null +++ b/OysterPhysics3D/Collision/BoxAxisAligned.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_BOXAXISALIGNED_H +#define OYSTER_COLLISION_BOXAXISALIGNED_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class BoxAxisAligned : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 minVertex, maxVertex; }; + char byte[2*sizeof(::Oyster::Math::Float3)]; + }; + + BoxAxisAligned( ); + BoxAxisAligned( const BoxAxisAligned &box ); + BoxAxisAligned( const ::Oyster::Math::Float3 &minVertex, const ::Oyster::Math::Float3 &maxVertex ); + BoxAxisAligned( const ::Oyster::Math::Float &leftClip, const ::Oyster::Math::Float &rightClip, const ::Oyster::Math::Float &topClip, const ::Oyster::Math::Float &bottomClip, const ::Oyster::Math::Float &nearClip, const ::Oyster::Math::Float &farClip ); + ~BoxAxisAligned( ); + + BoxAxisAligned & operator = ( const BoxAxisAligned &box ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Collision.cpp b/OysterPhysics3D/Collision/Collision.cpp new file mode 100644 index 00000000..41eea873 --- /dev/null +++ b/OysterPhysics3D/Collision/Collision.cpp @@ -0,0 +1,665 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Collision.h" +#include "Utilities.h" +#include + +using namespace Oyster::Math; + +namespace Oyster { namespace Collision { namespace Utility +{ + +// PRIVATE HEADER /////////////////////////////////////////////////// + namespace Private + { + const Float epsilon = (const Float)1e-20; + + // Float calculations can suffer roundingerrors. Which is where epsilon = 1e-20 comes into the picture + inline bool equalsZero( const Float &value ) + { // by Dan Andersson + return ::Utility::Value::abs( value ) < epsilon; + } + + // Float calculations can suffer roundingerrors. Which is where epsilon = 1e-20 comes into the picture + inline bool notEqualsZero( const Float &value ) + { // by Dan Andersson + return ::Utility::Value::abs( value ) > epsilon; + } + + // returns true if miss/reject + bool boxVsRayPerSlabCheck( const Float3 &axis, const Float &boundingOffset, const Float3 &deltaPos, const Float3 rayDirection, Float &tMin, Float &tMax ) + { // by Dan Andersson + Float e = axis.dot( deltaPos ), + f = axis.dot( rayDirection ); + if( equalsZero(f) ) // if axis is not parallell with ray + { + Float t1 = e + boundingOffset, + t2 = e - boundingOffset; + t1 /= f; t2 /= f; + if( t1 > t2 ) ::Utility::Element::swap( t1, t2 ); + tMin = ::Utility::Value::max( tMin, t1 ); + tMax = ::Utility::Value::min( tMax, t2 ); + if( tMin > tMax ) return true; + if( tMax < 0.0f ) return true; + } + else if( boundingOffset < -e ) return true; + else if( boundingOffset < e ) return true; + + return false; + } + + inline bool contains( const Plane &container, const Float3 &pos ) + { // by Dan Andersson + return equalsZero( container.normal.dot( pos ) + container.phasing ); + } + + inline void compare( Float &connectOffset, const Plane &plane, const Float3 &pos ) + { // by Dan Andersson + connectOffset = plane.normal.dot(pos); + connectOffset += plane.phasing; + } + + void compare( Float &boxExtend, Float ¢erDistance, const Plane &plane, const BoxAxisAligned &box ) + { // by Dan Andersson + Float3 c = (box.maxVertex + box.minVertex) * 0.5f, // box.Center + h = (box.maxVertex - box.minVertex) * 0.5f; // box.halfSize + boxExtend = h.x * ::Utility::Value::abs(plane.normal.x); // Box max extending towards plane + boxExtend += h.y * ::Utility::Value::abs(plane.normal.y); + boxExtend += h.z * ::Utility::Value::abs(plane.normal.z); + centerDistance = c.dot(plane.normal) + plane.phasing; // distance between box center and plane + } + + void compare( Float &boxExtend, Float ¢erDistance, const Plane &plane, const Box &box ) + { // by Dan Andersson + boxExtend = box.boundingOffset.x * ::Utility::Value::abs(plane.normal.dot(box.orientation.v[0].xyz)); // Box max extending towards plane + boxExtend += box.boundingOffset.y * ::Utility::Value::abs(plane.normal.dot(box.orientation.v[1].xyz)); + boxExtend += box.boundingOffset.z * ::Utility::Value::abs(plane.normal.dot(box.orientation.v[2].xyz)); + + centerDistance = box.orientation.v[3].xyz.dot(plane.normal) + plane.phasing; // distance between box center and plane + } + + bool fifteenAxisVsAlignedAxisOverlappingChecks( const Float3 &boundingOffsetA, const Float3 &boundingOffsetB, const Float4x4 &orientationB ) + { // by Dan Andersson + Float4x4 absOrientationB; + { + Float4x4 tO = orientationB.getTranspose(); + absOrientationB.v[0] = ::Utility::Value::abs(tO.v[0]); + if( absOrientationB.v[0].w > boundingOffsetA.x + boundingOffsetB.dot(absOrientationB.v[0].xyz) ) return false; + absOrientationB.v[1] = ::Utility::Value::abs(tO.v[1]); + if( absOrientationB.v[1].w > boundingOffsetA.y + boundingOffsetB.dot(absOrientationB.v[1].xyz) ) return false; + absOrientationB.v[2] = ::Utility::Value::abs(tO.v[2]); + if( absOrientationB.v[2].w > boundingOffsetA.z + boundingOffsetB.dot(absOrientationB.v[2].xyz) ) return false; + } + + absOrientationB.transpose(); + if( ::Utility::Value::abs(orientationB.v[3].dot(orientationB.v[0])) > boundingOffsetB.x + boundingOffsetA.dot(absOrientationB.v[0].xyz) ) return false; + if( ::Utility::Value::abs(orientationB.v[3].dot(orientationB.v[1])) > boundingOffsetB.x + boundingOffsetA.dot(absOrientationB.v[1].xyz) ) return false; + if( ::Utility::Value::abs(orientationB.v[3].dot(orientationB.v[2])) > boundingOffsetB.x + boundingOffsetA.dot(absOrientationB.v[2].xyz) ) return false; + + // ( 1,0,0 ) x orientationB.v[0].xyz: + Float d = boundingOffsetA.y * absOrientationB.v[0].z; + d += boundingOffsetA.z * absOrientationB.v[0].y; + d += boundingOffsetB.y * absOrientationB.v[2].x; + d += boundingOffsetB.z * absOrientationB.v[1].x; + if( ::Utility::Value::abs(orientationB.v[3].z*orientationB.v[0].y - orientationB.v[3].y*orientationB.v[0].z) > d ) return false; + + // ( 1,0,0 ) x orientationB.v[1].xyz: + d = boundingOffsetA.y * absOrientationB.v[1].z; + d += boundingOffsetA.z * absOrientationB.v[1].y; + d += boundingOffsetB.x * absOrientationB.v[2].x; + d += boundingOffsetB.z * absOrientationB.v[0].x; + if( ::Utility::Value::abs(orientationB.v[3].z*orientationB.v[1].y - orientationB.v[3].y*orientationB.v[1].z) > d ) return false; + + // ( 1,0,0 ) x orientationB.v[2].xyz: + d = boundingOffsetA.y * absOrientationB.v[2].z; + d += boundingOffsetA.z * absOrientationB.v[2].y; + d += boundingOffsetB.x * absOrientationB.v[1].x; + d += boundingOffsetB.y * absOrientationB.v[0].x; + if( ::Utility::Value::abs(orientationB.v[3].z*orientationB.v[2].y - orientationB.v[3].y*orientationB.v[2].z) > d ) return false; + + // ( 0,1,0 ) x orientationB.v[0].xyz: + d = boundingOffsetA.x * absOrientationB.v[0].z; + d += boundingOffsetA.z * absOrientationB.v[0].x; + d += boundingOffsetB.y * absOrientationB.v[2].y; + d += boundingOffsetB.z * absOrientationB.v[1].y; + if( ::Utility::Value::abs(orientationB.v[3].x*orientationB.v[0].z - orientationB.v[3].z*orientationB.v[0].x) > d ) return false; + + // ( 0,1,0 ) x orientationB.v[1].xyz: + d = boundingOffsetA.x * absOrientationB.v[1].z; + d += boundingOffsetA.z * absOrientationB.v[1].x; + d += boundingOffsetB.x * absOrientationB.v[2].y; + d += boundingOffsetB.z * absOrientationB.v[0].y; + if( ::Utility::Value::abs(orientationB.v[3].x*orientationB.v[1].z - orientationB.v[3].z*orientationB.v[1].x) > d ) return false; + + // ( 0,1,0 ) x orientationB.v[2].xyz: + d = boundingOffsetA.x * absOrientationB.v[2].z; + d += boundingOffsetA.z * absOrientationB.v[2].x; + d += boundingOffsetB.x * absOrientationB.v[1].y; + d += boundingOffsetB.y * absOrientationB.v[0].y; + if( ::Utility::Value::abs(orientationB.v[3].x*orientationB.v[2].z - orientationB.v[3].z*orientationB.v[2].x) > d ) return false; + + // ( 0,0,1 ) x orientationB.v[0].xyz: + d = boundingOffsetA.x * absOrientationB.v[0].y; + d += boundingOffsetA.y * absOrientationB.v[0].x; + d += boundingOffsetB.y * absOrientationB.v[2].z; + d += boundingOffsetB.z * absOrientationB.v[1].z; + if( ::Utility::Value::abs(orientationB.v[3].y*orientationB.v[0].x - orientationB.v[3].x*orientationB.v[0].y) > d ) return false; + + // ( 0,0,1 ) x orientationB.v[1].xyz: + d = boundingOffsetA.x * absOrientationB.v[1].y; + d += boundingOffsetA.y * absOrientationB.v[1].x; + d += boundingOffsetB.x * absOrientationB.v[2].z; + d += boundingOffsetB.z * absOrientationB.v[0].z; + if( ::Utility::Value::abs(orientationB.v[3].y*orientationB.v[1].x - orientationB.v[3].x*orientationB.v[1].y) > d ) return false; + + // ( 0,0,1 ) x orientationB.v[2].xyz: + d = boundingOffsetA.x * absOrientationB.v[2].y; + d += boundingOffsetA.y * absOrientationB.v[2].x; + d += boundingOffsetB.x * absOrientationB.v[1].z; + d += boundingOffsetB.y * absOrientationB.v[0].z; + if( ::Utility::Value::abs(orientationB.v[3].y*orientationB.v[2].x - orientationB.v[3].x*orientationB.v[2].y) > d ) return false; + + return true; + } + } + +// PUBLIC BODY ////////////////////////////////////////////////////// + + void compare( Float &connectDistance, Float &connectOffsetSquared, const Ray &ray, const Point &point ) + { // by Dan Andersson + Float3 dP = point.position - ray.origin; + + connectDistance = dP.dot( ray.direction ); + connectDistance /= ray.direction.dot( ray.direction ); + + dP -= ( connectDistance * ray.direction ); + connectOffsetSquared = dP.dot( dP ); + } + + void compare( Float &connectDistanceA, Float &connectDistanceB, Float &connectOffsetSquared, const Ray &rayA, const Ray &rayB ) + { // by Dan Andersson + Float3 dP = rayB.origin - rayA.origin; + connectDistanceA = rayA.direction.dot( dP ); + connectDistanceA /= rayA.direction.dot( rayA.direction ); + + dP *= -1.0f; + connectDistanceB = rayB.direction.dot( dP ); + connectDistanceB /= rayB.direction.dot( rayB.direction ); + + dP = rayA.direction * connectDistanceA; + dP += rayA.origin; + dP -= rayB.direction * connectDistanceB; + dP -= rayB.origin; + + connectOffsetSquared = dP.dot( dP ); + } + + void compare( Float &connectOffset, const Plane &plane, const Point &point ) + { // by Dan Andersson + Private::compare( connectOffset, plane, point.position ); + } + + bool intersect( const Point &pointA, const Point &pointB ) + { // by Fredrick Johansson + if (pointA.position.x != pointB.position.x) return false; + if (pointA.position.y != pointB.position.y) return false; + if (pointA.position.z != pointB.position.z) return false; + return true; // Passed all tests, is in same position + } + + bool intersect( const Ray &ray, const Point &point, Float &connectDistance ) + { // by Dan Andersson + Float connectOffsetSquared; + compare( connectDistance, connectOffsetSquared, ray, point ); + + if( Private::equalsZero(connectOffsetSquared) ) + { + connectOffsetSquared = 0.0f; + return true; + } + + connectDistance = 0.0f; + return false; + } + + bool intersect( const Ray &rayA, const Ray &rayB, Float &connectDistanceA, Float &connectDistanceB ) + { // by Dan Andersson + Float connectOffsetSquared; + compare( connectDistanceA, connectDistanceB, connectOffsetSquared, rayA, rayB ); + + if( Private::equalsZero(connectOffsetSquared) ) + { + connectOffsetSquared = 0.0f; + return true; + } + + connectDistanceA = connectDistanceB = 0.0f; + return false; + } + + bool intersect( const Sphere &sphere, const Point &point ) + { // by Dan Andersson + Float3 dP = point.position - sphere.center; + if( dP.dot(dP) > (sphere.radius * sphere.radius) ) + return false; + return true; + } + + bool intersect( const Sphere &sphere, const Ray &ray, Float &connectDistance ) + {// by Dan Andersson + Float3 dP = sphere.center - ray.origin; + Float s = dP.dot( ray.direction ), + dSquared = dP.dot( dP ), + rSquared = sphere.radius * sphere.radius; + + if( dSquared <= rSquared ) { connectDistance = 0.0f; return true; } + else if( s < 0.0f ) { connectDistance = 0.0f; return false; } + + Float mSquared = dSquared - (s*s); + if( mSquared > rSquared ) { connectDistance = 0.0f; return false; } + + Float q = ::std::sqrt( rSquared - mSquared ); + if( dSquared > rSquared ) connectDistance = s - q; + else connectDistance = s + q; + + return true; + } + + bool intersect( const Sphere &sphereA, const Sphere &sphereB ) + { // by Fredrick Johansson + Float3 C = sphereA.center; + C -= sphereB.center; + Float r = (sphereA.radius + sphereB.radius); + + if (r*r >= C.dot(C)) + { + return true; // Intersect detected! + } + + return false; + } + + bool intersect( const Plane &plane, const Point &point ) + { // by Dan Andersson + Float connectOffset; + Private::compare( connectOffset, plane, point.position ); + return Private::equalsZero(connectOffset); + } + + bool intersect( const Plane &plane, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + Float c = plane.normal.dot(ray.direction); + if( Private::equalsZero(c) ) + { // ray is parallell with the plane. (ray direction orthogonal with the planar normal) + connectDistance = 0.0f; + return contains( plane, ray.origin ); + } + + connectDistance = -plane.phasing; + connectDistance -= plane.normal.dot( ray.origin ); + connectDistance /= c; + + if( connectDistance > 0.0f ) + return true; + + connectDistance = 0.0f; + return false; + } + + bool intersect( const Plane &plane, const Sphere &sphere ) + { // by Dan Andersson + Float connectOffset; + Private::compare( connectOffset, plane, sphere.center ); + return (connectOffset <= sphere.radius); + } + + bool intersect( const Plane &planeA, const Plane &planeB ) + { // by Dan Andersson + if( planeA.normal == planeB.normal ) // they are parallell + return (planeA.phasing == planeB.phasing); + else if( planeA.normal == -planeB.normal ) // they are still parallell + return (planeA.phasing == -planeB.phasing); + return true; // none parallell planes ALWAYS intersects somewhere + } + + bool intersect( const BoxAxisAligned &box, const Point &point ) + { // by Dan Andersson + if( point.position.x < box.minVertex.x ) return false; + if( point.position.x > box.maxVertex.x ) return false; + if( point.position.y < box.minVertex.y ) return false; + if( point.position.y > box.maxVertex.y ) return false; + if( point.position.z < box.minVertex.z ) return false; + if( point.position.z > box.maxVertex.z ) return false; + return true; + } + + bool intersect( const BoxAxisAligned &box, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + Float tMin = ::std::numeric_limits::max(), + tMax = -tMin; // initiating to extremevalues + + Float3 boundingOffset = ((box.maxVertex - box.minVertex) * 0.5f), + dP = ((box.maxVertex + box.minVertex) * 0.5f) - ray.origin; + if( Private::boxVsRayPerSlabCheck( Float3::standardUnitX, boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( Float3::standardUnitY, boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( Float3::standardUnitZ, boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + + if( tMin > 0.0f ) connectDistance = tMin; + else connectDistance = tMax; + return true; + } + + bool intersect( const BoxAxisAligned &box, const Sphere &sphere ) + { // by Dan Andersson + Float3 e = ::Utility::Value::max( box.minVertex - sphere.center, Float3::null ); + e += ::Utility::Value::max( sphere.center - box.maxVertex, Float3::null ); + + if( e.dot(e) > (sphere.radius * sphere.radius) ) return false; + return true; + } + + bool intersect( const BoxAxisAligned &box, const Plane &plane ) + { // by Dan Andersson + Float e, d; + Private::compare( e, d, plane, box ); + if( d - e > 0.0f ) return false; // is beneath + if( d + e < 0.0f ) return false; // is above + return true; + } + +// bool intersect( const BoxAxisAligned &box, const Triangle &triangle ) +// { return false; /* TODO */ } + + bool intersect( const BoxAxisAligned &boxA, const BoxAxisAligned &boxB ) + { // by Dan Andersson + if( boxA.maxVertex.x < boxB.minVertex.x ) return false; + if( boxA.minVertex.x > boxB.maxVertex.x ) return false; + if( boxA.maxVertex.y < boxB.minVertex.y ) return false; + if( boxA.minVertex.y > boxB.maxVertex.y ) return false; + if( boxA.maxVertex.z < boxB.minVertex.z ) return false; + if( boxA.minVertex.z > boxB.maxVertex.z ) return false; + return true; + } + + bool intersect( const Box &box, const Point &point ) + { // by Dan Andersson + Float3 dPos = point.position - box.orientation.v[3].xyz; + + Float coordinate = dPos.dot( box.orientation.v[0].xyz ); + if( coordinate > box.boundingOffset.x ) return false; + if( coordinate < -box.boundingOffset.x ) return false; + + coordinate = dPos.dot( box.orientation.v[1].xyz ); + if( coordinate > box.boundingOffset.y ) return false; + if( coordinate < -box.boundingOffset.y ) return false; + + coordinate = dPos.dot( box.orientation.v[2].xyz ); + if( coordinate > box.boundingOffset.z ) return false; + if( coordinate < -box.boundingOffset.z ) return false; + + return true; + } + + bool intersect( const Box &box, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + Float tMin = ::std::numeric_limits::max(), + tMax = -tMin; // initiating to extremevalues + + Float3 dP = box.center - ray.origin; + if( Private::boxVsRayPerSlabCheck( box.xAxis, box.boundingOffset.x, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( box.yAxis, box.boundingOffset.y, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + if( Private::boxVsRayPerSlabCheck( box.zAxis, box.boundingOffset.z, dP, ray.direction, tMin, tMax ) ) { connectDistance = 0.0f; return false; } + + if( tMin > 0.0f ) connectDistance = tMin; + else connectDistance = tMax; + return true; + } + + bool intersect( const Box &box, const Sphere &sphere ) + { // by Dan Andersson + Float3 e = sphere.center - box.orientation.v[3].xyz, + centerL = Float3( e.dot(box.orientation.v[0].xyz), e.dot(box.orientation.v[1].xyz), e.dot(box.orientation.v[2].xyz) ); + + e = ::Utility::Value::max( (box.boundingOffset + centerL)*=-1.0f, Float3::null ); + e += ::Utility::Value::max( centerL - box.boundingOffset, Float3::null ); + + if( e.dot(e) > (sphere.radius * sphere.radius) ) return false; + return true; + } + + bool intersect( const Box &box, const Plane &plane ) + {// by Dan Andersson + Float e, d; + Private::compare( e, d, plane, box ); + if( d - e > 0.0f ) return false; // is beneath + if( d + e < 0.0f ) return false; // is above + return true; + } + + bool intersect( const Box &boxA, const BoxAxisAligned &boxB ) + { // by Dan Andersson + Float3 alignedOffsetBoundaries = boxB.maxVertex - boxB.minVertex; + Float4x4 translated = boxA.orientation; + translated.v[3].xyz -= boxB.minVertex; + translated.v[3].xyz += alignedOffsetBoundaries * 0.5f; + alignedOffsetBoundaries = ::Utility::Value::abs(alignedOffsetBoundaries); + return Private::fifteenAxisVsAlignedAxisOverlappingChecks( alignedOffsetBoundaries, boxA.boundingOffset, translated ); + } + + bool intersect( const Box &boxA, const Box &boxB ) + { // by Dan Andersson + Float4x4 M; + inverseRigidBodyMatrix( M, boxA.orientation ); + transformMatrix( M, boxB.orientation, M ); + return Private::fifteenAxisVsAlignedAxisOverlappingChecks( boxA.boundingOffset, boxB.boundingOffset, M ); + } + + bool intersect( const Frustrum &frustrum, const Point &point ) + { // by Dan Andersson + Float connectOffset; + + Private::compare( connectOffset, frustrum.leftPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + Private::compare( connectOffset, frustrum.rightPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + Private::compare( connectOffset, frustrum.bottomPlane, point.position ); + if( connectOffset < 0.0f) return false; + + Private::compare( connectOffset, frustrum.topPlane, point.position ); + if( connectOffset < 0.0f) return false; + + Private::compare( connectOffset, frustrum.nearPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + Private::compare( connectOffset, frustrum.farPlane, point.position ); + if( connectOffset < 0.0f ) return false; + + return true; + } + + bool intersect( const Frustrum &frustrum, const Ray &ray, Float &connectDistance ) + { // by Dan Andersson + bool intersected = false; + Float distance = 0.0f; + connectDistance = ::std::numeric_limits::max(); + + if( intersect(frustrum.leftPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.rightPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.bottomPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.topPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.nearPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersect(frustrum.farPlane, ray, distance) ) + { + intersected = true; + connectDistance = ::Utility::Value::min( connectDistance, distance ); + } + + if( intersected ) return true; + + connectDistance = 0.0f; + return false; + } + + bool intersect( const Frustrum &frustrum, const Sphere &sphere ) + { // by Dan Andersson + Float connectOffset; + + Private::compare( connectOffset, frustrum.leftPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.rightPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.bottomPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.topPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.nearPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + Private::compare( connectOffset, frustrum.farPlane, sphere.center ); + if( connectOffset < -sphere.radius ) return false; + + return true; + } + + bool intersect( const Frustrum &frustrum, const Plane &plane ) + { + return false; // TODO + } + +// bool intersect( const Frustrum &frustrum, const Triangle &triangle, ? ); + + bool intersect( const Frustrum &frustrum, const BoxAxisAligned &box ) + { // by Dan Andersson + Float e, d; + + Private::compare( e, d, frustrum.leftPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.rightPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.bottomPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.topPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.nearPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.farPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + return true; + } + + bool intersect( const Frustrum &frustrum, const Box &box ) + { // by Dan Andersson + Float e, d; + + Private::compare( e, d, frustrum.leftPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.rightPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.bottomPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.topPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.nearPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + Private::compare( e, d, frustrum.farPlane, box ); + if( d - e > 0.0f ) return false; // is beneath + + return true; + } + + bool intersect( const Frustrum &frustrumA, const Frustrum &frustrumB ) + { + return false; // TODO + } + + bool contains( const Ray &container, const Ray &ray ) + { + return false; /*TODO*/ + } + + bool contains( const Sphere &sphereA, const Sphere &sphereB ) + { // by Fredrick Johansson + // Check if SphereB is larger than sphereA + if (sphereA.radius < sphereB.radius) + { + return false; // Is impossible, yes + } + + // Calc distance from center to center + Float3 d = sphereB.center - sphereA.center; + Float deltaR = sphereA.radius - sphereB.radius; + + // Check if contained + if (d.dot(d) <= (deltaR*deltaR)) + { + return true; + } + + // Not contained + return false; + } + + bool contains( const Plane &container, const Point &point ) + { // by Dan Andersson + return Private::contains( container, point.position ); + } + + bool contains( const Plane &container, const Ray &ray ) + { // by Dan Andersson + if( Private::notEqualsZero(container.normal.dot(ray.direction)) ) return false; + return contains( container, ray.origin ); + } + + bool contains( const Plane &container, const Plane &plane ) + { // by Dan Andersson + if( container.phasing == plane.phasing ) + return container.normal == plane.normal; + if( container.phasing == -plane.phasing ) + return container.normal == -plane.normal; + return false; + } +} } } \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Collision.h b/OysterPhysics3D/Collision/Collision.h new file mode 100644 index 00000000..cd1838e4 --- /dev/null +++ b/OysterPhysics3D/Collision/Collision.h @@ -0,0 +1,104 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_UTILITY_H +#define OYSTER_COLLISION_UTILITY_H + +#include "ICollideable.h" +#include "Point.h" +#include "Ray.h" +#include "Sphere.h" +#include "Plane.h" +//#include "Triangle.h" +#include "BoxAxisAligned.h" +#include "Box.h" +#include "Frustrum.h" + +namespace Oyster { namespace Collision { namespace Utility +{ + void compare( ::Oyster::Math::Float &connectDistance, ::Oyster::Math::Float &connectOffsetSquared, const Ray &ray, const Point &point ); + void compare( ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB, ::Oyster::Math::Float &connectOffsetSquared, const Ray &rayA, const Ray &rayB ); + void compare( ::Oyster::Math::Float &connectOffset, const Plane &plane, const Point &point ); + + bool intersect( const Point &pointA, const Point &pointB ); + + bool intersect( const Ray &ray, const Point &point, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Ray &rayA, const Ray &rayB, ::Oyster::Math::Float &connectDistanceA, ::Oyster::Math::Float &connectDistanceB ); + + bool intersect( const Sphere &sphere, const Point &point ); + bool intersect( const Sphere &sphere, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Sphere &sphereA, const Sphere &sphereB ); + + bool intersect( const Plane &plane, const Point &point ); + bool intersect( const Plane &plane, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Plane &plane, const Sphere &sphere ); + bool intersect( const Plane &planeA, const Plane &planeB ); + +// bool intersect( const Triangle &triangle, const Point &point, ? ); +// bool intersect( const Triangle &triangle, const Ray &ray, ? ); +// bool intersect( const Triangle &triangle, const Sphere &sphere, ? ); +// bool intersect( const Triangle &triangle, const Plane &plane, ? ); +// bool intersect( const Triangle &triangleA, const Triangle &triangleB, ? ); + + bool intersect( const BoxAxisAligned &box, const Point &point ); + bool intersect( const BoxAxisAligned &box, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const BoxAxisAligned &box, const Sphere &sphere ); + bool intersect( const BoxAxisAligned &box, const Plane &plane ); +// bool intersect( const BoxAxisAligned &box, const Triangle &triangle ); + bool intersect( const BoxAxisAligned &boxA, const BoxAxisAligned &boxB ); + + bool intersect( const Box &box, const Point &point ); + bool intersect( const Box &box, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Box &box, const Sphere &sphere ); + bool intersect( const Box &box, const Plane &plane ); +// bool intersect( const Box &box, const Triangle &triangle, ? ); + bool intersect( const Box &boxA, const BoxAxisAligned &boxB ); + bool intersect( const Box &boxA, const Box &boxB ); + + bool intersect( const Frustrum &frustrum, const Point &point ); + bool intersect( const Frustrum &frustrum, const Ray &ray, ::Oyster::Math::Float &connectDistance ); + bool intersect( const Frustrum &frustrum, const Sphere &sphere ); + bool intersect( const Frustrum &frustrum, const Plane &plane ); +// bool intersect( const Frustrum &frustrum, const Triangle &triangle, ? ); + bool intersect( const Frustrum &frustrum, const BoxAxisAligned &box ); + bool intersect( const Frustrum &frustrum, const Box &box ); + bool intersect( const Frustrum &frustrumA, const Frustrum &frustrumB ); + + bool contains( const Ray &container, const Ray &ray ); + + bool contains( const Sphere &container, const Sphere &sphere ); +// bool contains( const Sphere &container, const Triangle &triangle ); +// bool contains( const Sphere &container, const BoxAxisAligned &box ); +// bool contains( const Sphere &container, const Box &box ); +// bool contains( const Sphere &container, const Frustrum &frustrum ); + + bool contains( const Plane &container, const Point &point ); + bool contains( const Plane &container, const Ray &ray ); + bool contains( const Plane &container, const Plane &plane ); +// bool contains( const Plane &container, const Triangle &triangle ); + +// bool contains( const Triangle &container, const Point &point ); +// bool contains( const Triangle &container, const Triangle &triangle ); + +// bool contains( const BoxAxisAligned &container, const Sphere &sphere ); +// bool contains( const BoxAxisAligned &container, const Triangle &triangle ); +// bool contains( const BoxAxisAligned &container, const BoxAxisAligned &box ); +// bool contains( const BoxAxisAligned &container, const Box &box ); +// bool contains( const BoxAxisAligned &container, const Frustrum &frustrum ); + +// bool contains( const Box &container, const Sphere &sphere ); +// bool contains( const Box &container, const Triangle &triangle ); +// bool contains( const Box &container, const BoxAxisAligned &box ); +// bool contains( const Box &container, const Box &box ); +// bool contains( const Box &container, const Frustrum &frustrum ); + +// bool contains( const Frustrum &container, const Sphere &sphere ); +// bool contains( const Frustrum &container, const Triangle &triangle ); +// bool contains( const Frustrum &container, const BoxAxisAligned &box ); +// bool contains( const Frustrum &container, const Box &box ); +// bool contains( const Frustrum &container, const Frustrum &frustrum ); +} } } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Frustrum.cpp b/OysterPhysics3D/Collision/Frustrum.cpp new file mode 100644 index 00000000..3e99db90 --- /dev/null +++ b/OysterPhysics3D/Collision/Frustrum.cpp @@ -0,0 +1,234 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Frustrum.h" +#include "Collision.h" + +using namespace Oyster::Math; +using namespace Oyster::Collision; + +namespace PrivateStatic +{ + inline void vpToPlanes( Plane &lp, Plane &rp, Plane &bp, Plane &tp, Plane &np, Plane &fp, const Float4x4 &vp ) + { + Float4x4 m = vp.getTranspose(); + + // left + lp.normal = m.v[3].xyz + m.v[0].xyz; + lp.phasing = lp.normal.length(); + lp.normal /= lp.phasing; + lp.phasing = (m.v[3].w + m.v[0].w) / lp.phasing; + + // right + rp.normal = m.v[3].xyz - m.v[0].xyz; + rp.phasing = rp.normal.length(); + rp.normal /= rp.phasing; + rp.phasing = (m.v[3].w - m.v[0].w) / rp.phasing; + + // bottom + bp.normal = m.v[3].xyz + m.v[1].xyz; + bp.phasing = bp.normal.length(); + bp.normal /= bp.phasing; + bp.phasing = (m.v[3].w + m.v[1].w) / bp.phasing; + + // top + tp.normal = m.v[3].xyz - m.v[1].xyz; + tp.phasing = tp.normal.length(); + tp.normal /= tp.phasing; + tp.phasing = (m.v[3].w - m.v[1].w) / tp.phasing; + + // near leftHanded DirectX + np.normal = m.v[2].xyz; + np.phasing = np.normal.length(); + np.normal /= np.phasing; + np.phasing = m.v[2].w / np.phasing; + + // far lefthanded + fp.normal = m.v[3].xyz - m.v[2].xyz; + fp.phasing = fp.normal.length(); + fp.normal /= fp.phasing; + fp.phasing = (m.v[3].w - m.v[2].w) / fp.phasing; + + /*/ near rightHanded openGL + np.normal = m.v[3].xyz + m.v[2].xyz; + np.phasing = np.normal.length(); + np.normal /= np.phasing; + np.phasing = -(m.v[3].w + m.v[2].w) / np.phasing; + + // far rightHanded + fp.normal = m.v[3].xyz - m.v[2].xyz; + fp.phasing = fp.normal.length(); + fp.normal /= fp.phasing; + fp.phasing = -(m.v[3].w - m.v[2].w) / fp.phasing;*/ + } + + void interpolatePlanes( Plane &target, const Plane &planeA, const Plane &planeB, float interpolation ) + { + float counterInterpol = 1.0f - interpolation; + target.normal = counterInterpol * planeA.normal; + target.normal += interpolation * planeB.normal; + target.phasing = counterInterpol * planeA.phasing; + target.phasing += interpolation * planeB.phasing; + target.normal.normalize(); + } +} + +Frustrum::Frustrum( ) : ICollideable(ICollideable::Frustrum), + leftPlane(Float3::standardUnitX, -0.5f), rightPlane(-Float3::standardUnitX, 0.5f), + bottomPlane(Float3::standardUnitY, -0.5f), topPlane(-Float3::standardUnitY, 0.5f), + nearPlane(Float3::standardUnitZ, -0.5f), farPlane(-Float3::standardUnitZ, 0.5f) {} + +Frustrum::Frustrum( const Frustrum &frustrum ) : ICollideable(ICollideable::Frustrum), + leftPlane(frustrum.leftPlane), rightPlane(frustrum.rightPlane), + bottomPlane(frustrum.bottomPlane), topPlane(frustrum.topPlane), + nearPlane(frustrum.nearPlane), farPlane(frustrum.farPlane) {} + +Frustrum::Frustrum( const Float4x4 &vp ) : ICollideable(ICollideable::Frustrum) +{ PrivateStatic::vpToPlanes( this->leftPlane, this->rightPlane, this->bottomPlane, this->topPlane, this->nearPlane, this->farPlane, vp ); } + +Frustrum::~Frustrum( ) {} + +Frustrum & Frustrum::operator = ( const Frustrum &frustrum ) +{ + this->leftPlane = frustrum.leftPlane; + this->rightPlane = frustrum.rightPlane; + this->bottomPlane = frustrum.bottomPlane; + this->topPlane = frustrum.topPlane; + this->nearPlane = frustrum.nearPlane; + this->farPlane = frustrum.farPlane; + return *this; +} + +Frustrum & Frustrum::operator = ( const Float4x4 &vp ) +{ + PrivateStatic::vpToPlanes( this->leftPlane, this->rightPlane, this->bottomPlane, this->topPlane, this->nearPlane, this->farPlane, vp ); + return *this; +} + +void Frustrum::split( Frustrum target[], unsigned int numX, unsigned int numY, unsigned int numZ ) const +{ + float incrementX = 1.0f / numX, + incrementY = 1.0f / numY, + incrementZ = 1.0f / numZ, + interpolX = 0.0f, + interpolY = 0.0f, + interpolZ = 0.0f; + + unsigned int i = 0U, + stepY = numX, + stepZ = numX * numY; + + Collision::Plane invRight( -this->rightPlane.normal, -this->rightPlane.phasing ), + invBottom( -this->bottomPlane.normal, -this->bottomPlane.phasing ), + invFar( -this->farPlane.normal, -this->farPlane.phasing ); + + for( unsigned int iz = 0U; iz < numZ; ++iz ) + { + interpolY = 0.0f; + for( unsigned int iy = 0U; iy < numY; ++iy ) + { + interpolX = 0.0f; + for( unsigned int ix = 0U; ix < numX; ++ix ) + { + if( ix == 0 ) + target[i].leftPlane = this->leftPlane; + else + { + PrivateStatic::interpolatePlanes( target[i].leftPlane, this->leftPlane, invRight, interpolX ); + + unsigned int iLeft = i - 1; + target[iLeft].rightPlane.normal = -target[i].leftPlane.normal; + target[iLeft].rightPlane.phasing = -target[i].leftPlane.phasing; + } + if( ix == numX - 1 ) + target[i].rightPlane = this->rightPlane; + + if( iy == 0 ) + target[i].topPlane = this->topPlane; + else + { + PrivateStatic::interpolatePlanes( target[i].topPlane, this->topPlane, invBottom, interpolY ); + + unsigned int iAbove = i - stepY; + target[iAbove].bottomPlane.normal = -target[i].topPlane.normal; + target[iAbove].bottomPlane.phasing = -target[i].topPlane.phasing; + } + if( iy == numY - 1 ) + target[i].bottomPlane = this->bottomPlane; + + if( iz == 0 ) + target[i].nearPlane = this->nearPlane; + else + { + PrivateStatic::interpolatePlanes( target[i].nearPlane, this->nearPlane, invFar, interpolZ ); + + unsigned int iCloser = i - stepZ; + target[iCloser].farPlane.normal = -target[i].nearPlane.normal; + target[iCloser].farPlane.phasing = -target[i].nearPlane.phasing; + } + if( iz == numZ - 1 ) + target[i].farPlane = this->farPlane; + + ++i; + interpolX += incrementX; + } + interpolY += incrementY; + } + interpolZ += incrementZ; + } +} + +void Frustrum::writeToByte( unsigned char targetMem[], unsigned int &nextIndex ) const +{ + Float *fMem = (Float*)&targetMem[nextIndex]; + for( int p = 0; p < 6; ++p ) + { + fMem[0] = this->plane[p].element[0]; + fMem[1] = this->plane[p].element[1]; + fMem[2] = this->plane[p].element[2]; + fMem[3] = this->plane[p].element[3]; + fMem = &fMem[4]; + } + nextIndex += 6 * ::Utility::StaticArray::numElementsOf( this->plane[0].byte ); +} + +ICollideable* Frustrum::clone( ) const +{ return new Frustrum(*this); } + +bool Frustrum::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *this, *(Collision::BoxAxisAligned*)target ); + case ICollideable::Box: return Utility::intersect( *this, *(Collision::Box*)target ); + case ICollideable::Frustrum: return Utility::intersect( *this, *(Collision::Frustrum*)target ); + case ICollideable::Line: return false; // TODO + default: return false; + } +} + +bool Frustrum::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return false; // TODO + case ICollideable::Sphere: return false; // TODO + case ICollideable::Plane: return false; // TODO + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + case ICollideable::Line: return false; // TODO + default: return false; + } +} + +ICollideable::State Frustrum::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Frustrum.h b/OysterPhysics3D/Collision/Frustrum.h new file mode 100644 index 00000000..5610356d --- /dev/null +++ b/OysterPhysics3D/Collision/Frustrum.h @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_FRUSTRUM_H +#define OYSTER_COLLISION_FRUSTRUM_H + +#include "OysterMath.h" +#include "ICollideable.h" +#include "Plane.h" + +namespace Oyster { namespace Collision +{ + + class Frustrum : public ICollideable + { + public: + + union + { + struct{ class Plane plane[6]; }; + struct + { class Plane leftPlane, rightPlane, bottomPlane, topPlane, nearPlane, farPlane; }; + }; + + Frustrum( ); + Frustrum( const Frustrum &frustrum ); + Frustrum( const ::Oyster::Math::Float4x4 &viewProjection ); + ~Frustrum( ); + + Frustrum & operator = ( const Frustrum &frustrum ); + Frustrum & operator = ( const ::Oyster::Math::Float4x4 &viewProjection ); + + void split( Frustrum targetList[], unsigned int numX, unsigned int numY = 1U, unsigned int numZ = 1u ) const; + void writeToByte( unsigned char targetMem[], unsigned int &nextIndex ) const; + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/ICollideable.h b/OysterPhysics3D/Collision/ICollideable.h new file mode 100644 index 00000000..1aa1a195 --- /dev/null +++ b/OysterPhysics3D/Collision/ICollideable.h @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////// +// Created by Pär Hammarstrand 2013 +// Edited by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_ICOLLIDEABLE_H +#define OYSTER_COLLISION_ICOLLIDEABLE_H + +namespace Oyster { namespace Collision +{ + class ICollideable + { + public: + enum CollisionType + { + Point, + Ray, + Sphere, + Plane, + Triangle, + BoxAxisAligned, + Box, + Frustrum, + Line + }; + + enum State + { + Missed = 0, + Contained, + Intersected + }; + + ICollideable( CollisionType _type ) : type(_type) {}; + + const CollisionType type; + + virtual ICollideable* clone( ) const = 0; + + virtual bool Intersects( const ICollideable *target ) const = 0; + + virtual bool Contains( const ICollideable *target ) const = 0; + + //Not supported returns 0; + virtual State Advanced( const ICollideable *target ) const = 0; + }; +} } +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Line.cpp b/OysterPhysics3D/Collision/Line.cpp new file mode 100644 index 00000000..47ab884e --- /dev/null +++ b/OysterPhysics3D/Collision/Line.cpp @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Line.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Line::Line( ) : ICollideable(ICollideable::Line), ray(), length(0.0f) {} +Line::Line( const Line &_line ) : ICollideable(ICollideable::Line), ray(_line.ray), length(_line.length) {} +Line::Line( const class Ray &_ray, const Float &_length ) : ICollideable(ICollideable::Line), ray(_ray), length(_length) {} +Line::Line( const Float3 &origin, const Float3 &normalizedDirection, const Float &_length ) : ICollideable(ICollideable::Line), ray(origin, normalizedDirection), length(_length) {} +Line::~Line( ) { /*Nothing needs to be done here*/ } + +Line & Line::operator = ( const Line &line ) +{ + this->ray = line.ray; + this->length = line.length; + return *this; +} + +ICollideable* Line::clone( ) const +{ return new Line(*this); } + +bool Line::Intersects( const ICollideable *target ) const +{ + if( this->ray.Intersects( target ) ) if( this->ray.collisionDistance >= 0.0f ) if( this->ray.collisionDistance <= this->length ) + return true; + + this->ray.collisionDistance = 0.0f; + return false; +} + +bool Line::Contains( const ICollideable *target ) const +{ /*TODO*/ return false; } + +ICollideable::State Line::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Line.h b/OysterPhysics3D/Collision/Line.h new file mode 100644 index 00000000..1cfa92a5 --- /dev/null +++ b/OysterPhysics3D/Collision/Line.h @@ -0,0 +1,39 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_LINE_H +#define OYSTER_COLLISION_LINE_H + +#include "OysterMath.h" +#include "ICollideable.h" +#include "Ray.h" + +namespace Oyster { namespace Collision +{ + class Line : public ICollideable + { + public: + union + { + struct { class Ray ray; ::Oyster::Math::Float length; }; + char byte[sizeof(class Ray) + sizeof(::Oyster::Math::Float)]; + }; + + Line( ); + Line( const Line &line ); + Line( const class Ray &ray, const ::Oyster::Math::Float &length ); + Line( const ::Oyster::Math::Float3 &origin, const ::Oyster::Math::Float3 &normalizedDirection, const ::Oyster::Math::Float &length ); + ~Line( ); + + Line & operator = ( const Line &line ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/OysterCollision.h b/OysterPhysics3D/Collision/OysterCollision.h new file mode 100644 index 00000000..051fddea --- /dev/null +++ b/OysterPhysics3D/Collision/OysterCollision.h @@ -0,0 +1,11 @@ +#include "ICollideable.h" +#include "Point.h" +#include "Ray.h" +#include "Plane.h" +#include "Sphere.h" +#include "BoxAxisAligned.h" +#include "Box.h" +#include "Frustrum.h" +#include "Line.h" + +#include "Collision.h" \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Plane.cpp b/OysterPhysics3D/Collision/Plane.cpp new file mode 100644 index 00000000..6a60ea0a --- /dev/null +++ b/OysterPhysics3D/Collision/Plane.cpp @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Plane.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Plane::Plane( ) : ICollideable(ICollideable::Plane), normal(), phasing(0.0f) {} +Plane::Plane( const Plane &plane ) : ICollideable(ICollideable::Plane), normal(plane.normal), phasing(plane.phasing) {} +Plane::Plane( const Float3 &n, const Float &p ) : ICollideable(ICollideable::Plane), normal(n), phasing(p) {} +Plane::~Plane( ) { /*Nothing needs to be done here*/ } + +Plane & Plane::operator = ( const Plane &plane ) +{ + this->normal = plane.normal; + this->phasing = plane.phasing; + return *this; +} + +ICollideable* Plane::clone( ) const +{ return new Plane( *this ); } + +bool Plane::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this ); + case ICollideable::Frustrum: return false; // TODO + case ICollideable::Line: return false; // TODO + default: return false; + } +} + +bool Plane::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::contains( *this, *(Collision::Ray*)target ); + case ICollideable::Plane: return Utility::contains( *this, *(Collision::Plane*)target ); + case ICollideable::Triangle: return false; // TODO + default: return false; + } +} + +ICollideable::State Plane::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Plane.h b/OysterPhysics3D/Collision/Plane.h new file mode 100644 index 00000000..8dc4e894 --- /dev/null +++ b/OysterPhysics3D/Collision/Plane.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_PLANE_H +#define OYSTER_COLLISION_PLANE_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Plane : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 normal; ::Oyster::Math::Float phasing; }; + ::Oyster::Math::Float element[4]; + char byte[sizeof(::Oyster::Math::Float3) + sizeof(::Oyster::Math::Float)]; + }; + + Plane( ); + Plane( const Plane &plane ); + Plane( const ::Oyster::Math::Float3 &normal, const ::Oyster::Math::Float &phasing ); + ~Plane( ); + + Plane & operator = ( const Plane &plane ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Point.cpp b/OysterPhysics3D/Collision/Point.cpp new file mode 100644 index 00000000..6a239ae2 --- /dev/null +++ b/OysterPhysics3D/Collision/Point.cpp @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Point.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Point::Point( ) : ICollideable(ICollideable::Point), position() {} +Point::Point( const Point &point ) : ICollideable(ICollideable::Point), position(point.position) {} +Point::Point( const Float3 &pos ) : ICollideable(ICollideable::Point), position(pos) {} +Point::~Point( ) { /*Nothing needs to be done here*/ } + +Point & Point::operator = ( const Point &point ) +{ + this->position = point.position; + return *this; +} + +ICollideable* Point::clone( ) const +{ return new Point( *this ); } + +bool Point::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *(Collision::Ray*)target, *this, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: Utility::intersect( *(Collision::Sphere*)target, *this ); + case ICollideable::Plane: return Utility::intersect( *(Collision::Plane*)target, *this ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Point::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + default: return false; + } +} + +ICollideable::State Point::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Point.h b/OysterPhysics3D/Collision/Point.h new file mode 100644 index 00000000..079161da --- /dev/null +++ b/OysterPhysics3D/Collision/Point.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_POINT_H +#define OYSTER_COLLISION_POINT_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Point : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 position; }; + char byte[sizeof(::Oyster::Math::Float3)]; + }; + + Point( ); + Point( const Point &point ); + Point( const ::Oyster::Math::Float3 &position ); + ~Point( ); + + Point & operator = ( const Point &point ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Ray.cpp b/OysterPhysics3D/Collision/Ray.cpp new file mode 100644 index 00000000..56ea1c9a --- /dev/null +++ b/OysterPhysics3D/Collision/Ray.cpp @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#include "Ray.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Ray::Ray( ) : ICollideable(ICollideable::Ray), origin(), direction(), collisionDistance(0.0f) {} +Ray::Ray( const Ray &ray ) : ICollideable(ICollideable::Ray), origin(ray.origin), direction(ray.direction), collisionDistance(0.0f) {} +Ray::Ray( const Float3 &o, const ::Oyster::Math::Float3 &d ) : ICollideable(ICollideable::Ray), origin(o), direction(d), collisionDistance(0.0f) {} +Ray::~Ray( ) { /*Nothing needs to be done here*/ } + +Ray & Ray::operator = ( const Ray &ray ) +{ + this->origin = ray.origin; + this->direction = ray.direction; + this->collisionDistance = ray.collisionDistance; + return *this; +} + +ICollideable* Ray::clone( ) const +{ return new Ray( *this ); } + +bool Ray::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target, this->collisionDistance ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, this->collisionDistance, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: return Utility::intersect( *(Collision::Sphere*)target, *this, this->collisionDistance ); + case ICollideable::Plane: return Utility::intersect( *(Collision::Plane*)target, *this, this->collisionDistance ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this, this->collisionDistance ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this, this->collisionDistance ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Ray::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target, this->collisionDistance ); + case ICollideable::Ray: Utility::contains( *this, *(Collision::Ray*)target ); + default: return false; + } +} + +ICollideable::State Ray::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Ray.h b/OysterPhysics3D/Collision/Ray.h new file mode 100644 index 00000000..a0d88ce4 --- /dev/null +++ b/OysterPhysics3D/Collision/Ray.h @@ -0,0 +1,42 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +/* + Ray::direction is assumed to be normalized! + - Dan +*/ +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_RAY_H +#define OYSTER_COLLISION_RAY_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Ray : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 origin, direction; }; + char byte[2*sizeof(::Oyster::Math::Float3)]; + }; + mutable float collisionDistance; + + Ray( ); + Ray( const Ray &ray ); + Ray( const ::Oyster::Math::Float3 &origin, const ::Oyster::Math::Float3 &normalizedDirection ); + ~Ray( ); + + Ray & operator = ( const Ray &ray ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Sphere.cpp b/OysterPhysics3D/Collision/Sphere.cpp new file mode 100644 index 00000000..c6ccc31f --- /dev/null +++ b/OysterPhysics3D/Collision/Sphere.cpp @@ -0,0 +1,53 @@ +#include "Sphere.h" +#include "Collision.h" + +using namespace ::Oyster::Collision; +using namespace ::Oyster::Math; + +Sphere::Sphere( ) : ICollideable(ICollideable::Sphere), center(), radius(0.0f) { } +Sphere::Sphere( const Sphere &sphere ) : ICollideable(ICollideable::Sphere), center(sphere.center), radius(sphere.radius) {} +Sphere::Sphere( const Float3 &_position, const Float &_radius ) : ICollideable(ICollideable::Sphere), center(_position), radius(_radius) {} +Sphere::~Sphere( ) { /*Nothing needs to be done here*/ } + +Sphere & Sphere::operator = ( const Sphere &sphere ) +{ + this->center = sphere.center; + this->radius = sphere.radius; + return *this; +} + +ICollideable* Sphere::clone( ) const +{ return new Sphere( *this ); } + +bool Sphere::Intersects( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Ray: return Utility::intersect( *this, *(Collision::Ray*)target, ((Collision::Ray*)target)->collisionDistance ); + case ICollideable::Sphere: Utility::intersect( *this, *(Collision::Sphere*)target ); + case ICollideable::Plane: return Utility::intersect( *(Collision::Plane*)target, *this ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return Utility::intersect( *(Collision::BoxAxisAligned*)target, *this ); + case ICollideable::Box: return Utility::intersect( *(Collision::Box*)target, *this ); + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +bool Sphere::Contains( const ICollideable *target ) const +{ + switch( target->type ) + { + case ICollideable::Point: return Utility::intersect( *this, *(Collision::Point*)target ); + case ICollideable::Sphere: return Utility::contains( *this, *(Collision::Sphere*)target ); + case ICollideable::Triangle: return false; // TODO + case ICollideable::BoxAxisAligned: return false; // TODO + case ICollideable::Box: return false; // TODO + case ICollideable::Frustrum: return false; // TODO + default: return false; + } +} + +ICollideable::State Sphere::Advanced( const ICollideable *target ) const +{ return ICollideable::Missed; } //Not supported returns 0 \ No newline at end of file diff --git a/OysterPhysics3D/Collision/Sphere.h b/OysterPhysics3D/Collision/Sphere.h new file mode 100644 index 00000000..b33ad216 --- /dev/null +++ b/OysterPhysics3D/Collision/Sphere.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////// +// Created by Dan Andersson 2013 +///////////////////////////////////////////////////////////////////// + +#pragma once +#ifndef OYSTER_COLLISION_SPHERE_H +#define OYSTER_COLLISION_SPHERE_H + +#include "OysterMath.h" +#include "ICollideable.h" + +namespace Oyster { namespace Collision +{ + class Sphere : public ICollideable + { + public: + union + { + struct{ ::Oyster::Math::Float3 center; ::Oyster::Math::Float radius; }; + char byte[sizeof(::Oyster::Math::Float3) + sizeof(::Oyster::Math::Float)]; + }; + + Sphere( ); + Sphere( const Sphere &point ); + Sphere( const ::Oyster::Math::Float3 &position, const ::Oyster::Math::Float &radius ); + ~Sphere( ); + + Sphere & operator = ( const Sphere &sphere ); + + ICollideable* clone( ) const; + bool Intersects( const ICollideable *target ) const; + bool Contains( const ICollideable *target ) const; + ICollideable::State Advanced( const ICollideable *target ) const; //Not supported returns 0; + }; +} } + +#endif \ No newline at end of file diff --git a/WindowManager/Example Usage.cpp b/WindowManager/Example Usage.cpp new file mode 100644 index 00000000..b9f46550 --- /dev/null +++ b/WindowManager/Example Usage.cpp @@ -0,0 +1,148 @@ + +#include "WindowShell.h" + + + + +/******************************************** + * Callback for main window * + *******************************************/ +LRESULT CALLBACK +WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + + switch( msg ) + { + // Window is being destroyed. + case WM_DESTROY: + PostQuitMessage(0); + break; + + case WM_CREATE: + break; + + case WM_PAINT: + hdc = BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + break; + + // Prevent the window from becoming too small. + case WM_GETMINMAXINFO: + ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; + ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; + break; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + + + +/******************************************** + * Callback for children * + *******************************************/ +LRESULT CALLBACK +ChildWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + PAINTSTRUCT ps; + HDC hdc; + + switch( msg ) + { + // Window is being destroyed. + case WM_DESTROY: + WindowShell::self()->removeChild(hwnd); + break; + + case WM_CREATE: + break; + + case WM_PAINT: + hdc = BeginPaint(hwnd, &ps); + EndPaint(hwnd, &ps); + break; + + // Prevent the window from becoming too small. + case WM_GETMINMAXINFO: + ((MINMAXINFO*)lParam)->ptMinTrackSize.x = 100; + ((MINMAXINFO*)lParam)->ptMinTrackSize.y = 100; + break; + + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + + + +int WINAPI WinMain( HINSTANCE hInst, HINSTANCE prevInst, PSTR cmdLine, int cmdShow) +{ + _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); + + + +/******************************************** + * Description of a window * + *******************************************/ + WindowShell::INIT_DESC_WINDOW wDesc; + wDesc.hInstance = hInst; + wDesc.windowName = L"Glare"; + wDesc.windowPosition = Point2D(50); + wDesc.windowSize = Point2D(1024, 800); + wDesc.windowProcCallback = WndProc; + + + +/******************************************** + * Description of a child window * + *******************************************/ + WindowShell::INIT_DESC_CHILD_WINDOW cDesc; + cDesc.name = L"Child"; + cDesc.style = WS_EX_RIGHTSCROLLBAR; + cDesc.topLeftPos = Point2D(); + cDesc.windowProcCallback = ChildWndProc; + cDesc.windowSize = Point2D(80); + + + +/************************************************************ + * Initializing main window and several children * + ************************************************************/ + WindowShell::self()->createWin(wDesc); + WindowShell::self()->createChildWin(cDesc); + WindowShell::self()->createChildWin(cDesc); + WindowShell::self()->createChildWin(cDesc); + + + +/******************************************** + * The main application loop * + *******************************************/ + MSG msg = {0}; + while(msg.message != WM_QUIT) + { + // If there are Window messages process them. + if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + else + { + + } + } + + +/************************************************ + * Destroying the WindowShell singleton * + ***********************************************/ + WindowShell::destroy(); + + return cmdShow; +} diff --git a/WindowManager/Window.cpp b/WindowManager/Window.cpp new file mode 100644 index 00000000..3ff58129 --- /dev/null +++ b/WindowManager/Window.cpp @@ -0,0 +1,164 @@ +#include "Window.h" +#include + +using namespace Oyster; + +HWND Window::Handle = NULL; +std::stringstream Window::Log = std::stringstream(); +RECT Window::WindowRect = RECT(); +RECT Window::Size = RECT(); +RECT Window::ClientRect = RECT(); +WNDPROC Window::wndProc = NULL; +bool Window::isCaptured = false; +bool Window::shouldCapture = false; +int Window::OffsetMouseX=0; +int Window::OffsetMouseY=0; + +bool Window::init( const LPCSTR appName, const LPCSTR className, const HINSTANCE &hInstance, const int &nCmdShow, WNDPROC wProc, bool handleLoop ) +{ + if( Handle != NULL ) + { + Log<< "Faulty Init, First window Exists"; + return true; + } + + // Register window class + WNDCLASSEXA window = { 0 }; + window.cbSize = sizeof( WNDCLASSEXA ); + window.style = CS_HREDRAW | CS_VREDRAW; + window.lpfnWndProc = wProc; + if(handleLoop) + { + window.lpfnWndProc = Window::InputMethod; + Window::wndProc = wProc; + } + window.hInstance = hInstance; + window.hIcon = LoadIcon( NULL, IDI_APPLICATION ); + window.hCursor = LoadCursor( NULL, IDC_ARROW ); + window.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + window.lpszMenuName = NULL; + window.lpszClassName = className; + + if( !RegisterClassExA( &window ) ) + { + Log << "Failed to Register Window.\n"; + return false; + } + + Handle = CreateWindowEx( NULL, + className, + appName, + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, + CW_USEDEFAULT, + 800, //rc.right - rc.left, + 600, //rc.bottom - rc.top, + NULL, + NULL, + hInstance, + NULL ); + + if( Handle == NULL ) + { + Log << "Failed to Init Window.\n"; + return false; + } + WINDOWINFO wi; + wi.cbSize = sizeof(WINDOWINFO); + GetWindowInfo(Handle,&wi); + WindowRect = wi.rcClient; + Size.right = Size.left = WindowRect.right - WindowRect.left; + Size.top = Size.bottom = WindowRect.bottom - WindowRect.top; + ClientRect.left= ClientRect.top=0; + ClientRect.right = Size.left; + ClientRect.bottom = Size.top; + ShowWindow( Handle, nCmdShow ); + return true; +} + +void Window::deFocus( ) { SetFocus( GetDesktopWindow() ); } +bool Window::isInFocus( ) { return Handle == GetFocus( ); } +bool Window::mouseIsInWindow(POINT point ) +{ + return PtInRect( &WindowRect, point )!=0; +} + +LRESULT CALLBACK Window::InputMethod( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) +{ + switch (message) + { + + case WM_KEYDOWN: + Oyster::Input::Controller::KeyPressed(wParam); + break; + case WM_KEYUP: + Oyster::Input::Controller::KeyReleased(wParam); + break; + case WM_MOUSEMOVE: + if(!isCaptured) + if(shouldCapture) + SetCapture(Handle); + POINT pt; + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if(PtInRect(&ClientRect,pt)!=0) + Oyster::Input::Controller::MouseMove(GET_X_LPARAM(lParam)+OffsetMouseX,GET_Y_LPARAM(lParam)+OffsetMouseY); + else + { + if(shouldCapture) + { + pt.x = Input::Controller::GetX(); + pt.y = Input::Controller::GetY(); + ClientToScreen(Handle, &pt); + SetCursorPos(pt.x-OffsetMouseX,pt.y-OffsetMouseY); + } + } + break; + case WM_LBUTTONDOWN: + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_XBUTTONDOWN: + { + Oyster::Input::Controller::MouseBtnPressed(wParam); + break; + } + case WM_LBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(MK_LBUTTON); + break; + } + case WM_MBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(MK_MBUTTON); + break; + } + case WM_RBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(MK_RBUTTON); + break; + } + case WM_XBUTTONUP: + { + Oyster::Input::Controller::MouseBtnReleased(wParam); + break; + } + default: + return wndProc(hWnd, message, wParam, lParam); + } + + return 0; +} + +void Window::CaptureMouse(bool b) +{ + shouldCapture=b; + isCaptured=false; + if(!b) + SetCapture(NULL); +} + +void Window::SetMouseOffset(int x,int y) +{ + OffsetMouseX=x; + OffsetMouseY=y; +} \ No newline at end of file diff --git a/WindowManager/Window.h b/WindowManager/Window.h new file mode 100644 index 00000000..9ca7eb0b --- /dev/null +++ b/WindowManager/Window.h @@ -0,0 +1,46 @@ +#pragma once + +#define NOMINMAX // Because I hate Microsoft now. ~Angry Dan. +// http://lolengine.net/blog/2011/3/4/fuck-you-microsoft-near-far-macros + +#include +#include +#include +#include "..\Input\InputController.h" + +namespace Oyster +{ + namespace Input + { + class Controller; + } + class Window + { + friend class ::Oyster::Input::Controller; + private: + Window(); + ~Window(); + static void CaptureMouse(bool b = true); + static bool shouldCapture; + static bool isCaptured; + static int OffsetMouseX; + static int OffsetMouseY; + public: + static bool init( const LPCSTR appName, const LPCSTR className, const HINSTANCE &hInstance,const int &nCmdShow, WNDPROC wProc, bool ManageWindow=false ); + + static void deFocus( ); + static bool isInFocus( ); + static bool mouseIsInWindow(POINT point ); + + static HWND Handle; + static std::stringstream Log; + static RECT WindowRect; + static RECT Size; + static RECT ClientRect; + static WNDPROC wndProc; + + static LRESULT CALLBACK InputMethod(HWND h,UINT i, WPARAM w,LPARAM l); + + static void SetMouseOffset(int x,int y); + }; +} \ No newline at end of file diff --git a/WindowManager/WindowShell.cpp b/WindowManager/WindowShell.cpp new file mode 100644 index 00000000..836a350c --- /dev/null +++ b/WindowManager/WindowShell.cpp @@ -0,0 +1,276 @@ +#include "WindowShell.h" +#include + + +struct ChildWin; +struct _PrSt; + +#pragma region Declarations + + namespace + { + //Private data + static WindowShell* instance = NULL; + int childIdCounter = 0; + _PrSt *pData = NULL; + } + + struct ChildWin + { + int id; + HWND hWnd; + + ChildWin() + { + hWnd = NULL; + childIdCounter++; + id = childIdCounter; + } + int ID() const { return id; } + }; + struct _PrSt + { + HINSTANCE hIns; + HWND hWnd; + std::vector childWindows; + + _PrSt() + { + hIns = NULL; + hWnd = NULL; + } + }; + +#pragma endregion + + + +WindowShell::WindowShell() +{ + pData = new _PrSt(); +} +WindowShell::~WindowShell() +{ + delete pData; +} + + + +bool WindowShell::createWin(INIT_DESC_WINDOW &desc) +{ + if(pData->hWnd) + { + MessageBox(0, L"There is already a window registered\nPlease use child windows to create more windows!" ,L"Error", 0); + return false; + } + if(!desc.windowProcCallback) + { + MessageBox(0, L"No callback function for window messages was found!" ,L"Error", 0); + return false; + } + if(!desc.hInstance) + { + MessageBox(0, L"No HINSTANCE was specified!" ,L"Error", 0); + return false; + } + if(desc.windowSize < 0) + { + MessageBox(0, L"Size specified for window is invalid!" ,L"Error", 0); + } + + + pData->hIns = desc.hInstance; + + + #pragma region Register + + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.hIconSm = NULL; + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = desc.windowProcCallback; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = pData->hIns; + wc.hIcon = LoadIcon(0, IDI_APPLICATION); + wc.hCursor = LoadCursor(0, IDC_ARROW); + wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszMenuName = 0; + wc.lpszClassName = L"MainWindowClass"; + + if( !RegisterClassEx(&wc) ) + { + MessageBox(0, L"Failed to register class", L"Initialization error", 0); + return false; + } + #pragma endregion + + + #pragma region Create window + + + pData->hWnd = CreateWindow( + L"MainWindowClass" , + desc.windowName.c_str(), + WS_OVERLAPPEDWINDOW, + desc.windowPosition.x, + desc.windowPosition.y, + desc.windowSize.x, + desc.windowSize.y, + 0, + 0, + pData->hIns, + 0 + ); + + if( !pData->hWnd ) + { + MessageBox(0, L"Failed to create window", L"Error!", 0); + return false; + } + + #pragma endregion + + + //Show and update window + ShowWindow(pData->hWnd, SW_SHOW); + UpdateWindow(pData->hWnd); + + return true; +} +int WindowShell::createChildWin(INIT_DESC_CHILD_WINDOW &desc) +{ + ChildWin win; + + + char idStr[3]; + _itoa_s(win.id, idStr, 10); + std::string next = idStr; + std::wstring str = std::wstring(next.begin(), next.end()); + std::wstring childClassName = L"ChildWindow_"; + childClassName += str; + + WNDCLASSEX wcex; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_VREDRAW; + wcex.lpfnWndProc = desc.windowProcCallback; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = pData->hIns; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(0, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); + wcex.lpszMenuName = NULL; + wcex.lpszClassName = childClassName.c_str(); + wcex.hIconSm = NULL; + + if(!RegisterClassEx(&wcex)) + { + MessageBox(0, L"", 0, 0); + } + + if(!desc.style) + desc.style = WS_EX_CLIENTEDGE; + + win.hWnd = CreateWindowEx + ( + desc.style, + childClassName.c_str(), + desc.name.c_str(), + WS_CAPTION | WS_SYSMENU , + desc.topLeftPos.x, desc.topLeftPos.y, + desc.windowSize.x, desc.windowSize.y, + pData->hWnd, + NULL, + pData->hIns, + NULL + ); + + + if (win.hWnd) + { + pData->childWindows.push_back(win); + ShowWindow(win.hWnd, 5); + UpdateWindow(win.hWnd); + } + else + { + DWORD err = GetLastError(); + MessageBox(0, L"Failed to create child window", L"Error!", MB_OK); + return false; + } + + return win.id; +} +bool WindowShell::removeChild(int id) +{ + for (int i = 0; i < (int)pData->childWindows.size(); i++) + { + if(id == pData->childWindows[i].id) + { + pData->childWindows.erase(pData->childWindows.begin() + i); + return true; + } + } + + return false; +} +bool WindowShell::removeChild(HWND hwnd) +{ + for (int i = 0; i < (int)pData->childWindows.size(); i++) + { + if(hwnd == pData->childWindows[i].hWnd) + { + pData->childWindows.erase(pData->childWindows.begin() + i); + return true; + } + } + + return false; +} + + + +const HINSTANCE WindowShell::getHINSTANCE() const +{ + return pData->hIns; +} +const HWND WindowShell::getHWND() const +{ + return pData->hWnd; +} +const HWND WindowShell::getChildHWND(int id) const +{ + for(int i = 0; i<(int)pData->childWindows.size(); i++) + { + if(id == pData->childWindows[i].id) + return pData->childWindows[i].hWnd; + } + + return NULL; +} +const int WindowShell::getChildID(HWND hwnd) const +{ + for(int i = 0; i<(int)pData->childWindows.size(); i++) + { + if(hwnd == pData->childWindows[i].hWnd) + return pData->childWindows[i].id; + } + + return -1; +} + + + +WindowShell* WindowShell::self() +{ + if(!instance) + instance = new WindowShell(); + + return instance; +} +void WindowShell::destroy() +{ + delete instance; + instance = NULL; +} \ No newline at end of file diff --git a/WindowManager/WindowShell.h b/WindowManager/WindowShell.h new file mode 100644 index 00000000..267417be --- /dev/null +++ b/WindowManager/WindowShell.h @@ -0,0 +1,112 @@ +#ifndef GLARE_WINDOW_H +#define GLARE_WINDOW_H + +#include +#include + + +struct Point2D +{ + int x; + int y; + Point2D() + { + x = 0; + y = 0; + } + Point2D(int _x, int _y) + { + x = _x; + y = _y; + } + Point2D(int _p) + { + x = _p; + y = _p; + } + operator POINT() const + { + return Point2D(x, y); + } + bool operator<(int i) + { + bool a = x