diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1cf89d8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/*.vsconfig +/Library/ +/Temp/ +/UserSettings/ +/.vs/ +/*.csproj +/*.sln +/obj/ +/Logs/ +/log/ +/ProjectSettings/Packages/ \ No newline at end of file diff --git a/Assets/InputSystem_Actions.inputactions b/Assets/InputSystem_Actions.inputactions new file mode 100644 index 0000000..1a12cb9 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions @@ -0,0 +1,1057 @@ +{ + "name": "InputSystem_Actions", + "maps": [ + { + "name": "Player", + "id": "df70fa95-8a34-4494-b137-73ab6b9c7d37", + "actions": [ + { + "name": "Move", + "type": "Value", + "id": "351f2ccd-1f9f-44bf-9bec-d62ac5c5f408", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Look", + "type": "Value", + "id": "6b444451-8a00-4d00-a97e-f47457f736a8", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Attack", + "type": "Button", + "id": "6c2ab1b8-8984-453a-af3d-a3c78ae1679a", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Interact", + "type": "Button", + "id": "852140f2-7766-474d-8707-702459ba45f3", + "expectedControlType": "Button", + "processors": "", + "interactions": "Hold", + "initialStateCheck": false + }, + { + "name": "Crouch", + "type": "Button", + "id": "27c5f898-bc57-4ee1-8800-db469aca5fe3", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Jump", + "type": "Button", + "id": "f1ba0d36-48eb-4cd5-b651-1c94a6531f70", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Previous", + "type": "Button", + "id": "2776c80d-3c14-4091-8c56-d04ced07a2b0", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Next", + "type": "Button", + "id": "b7230bb6-fc9b-4f52-8b25-f5e19cb2c2ba", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Sprint", + "type": "Button", + "id": "641cd816-40e6-41b4-8c3d-04687c349290", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "", + "id": "978bfe49-cc26-4a3d-ab7b-7d7a29327403", + "path": "/leftStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "WASD", + "id": "00ca640b-d935-4593-8157-c05846ea39b3", + "path": "Dpad", + "interactions": "", + "processors": "", + "groups": "", + "action": "Move", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "e2062cb9-1b15-46a2-838c-2f8d72a0bdd9", + "path": "/w", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "8180e8bd-4097-4f4e-ab88-4523101a6ce9", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "320bffee-a40b-4347-ac70-c210eb8bc73a", + "path": "/s", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "1c5327b5-f71c-4f60-99c7-4e737386f1d1", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "d2581a9b-1d11-4566-b27d-b92aff5fabbc", + "path": "/a", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "2e46982e-44cc-431b-9f0b-c11910bf467a", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcfe95b8-67b9-4526-84b5-5d0bc98d6400", + "path": "/d", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "77bff152-3580-4b21-b6de-dcd0c7e41164", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Move", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "1635d3fe-58b6-4ba9-a4e2-f4b964f6b5c8", + "path": "/{Primary2DAxis}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3ea4d645-4504-4529-b061-ab81934c3752", + "path": "/stick", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Move", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c1f7a91b-d0fd-4a62-997e-7fb9b69bf235", + "path": "/rightStick", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8c8e490b-c610-4785-884f-f04217b23ca4", + "path": "/delta", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse;Touch", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "3e5f5442-8668-4b27-a940-df99bad7e831", + "path": "/{Hatswitch}", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Look", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "143bb1cd-cc10-4eca-a2f0-a3664166fe91", + "path": "/buttonWest", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "05f6913d-c316-48b2-a6bb-e225f14c7960", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "886e731e-7071-4ae4-95c0-e61739dad6fd", + "path": "/primaryTouch/tap", + "interactions": "", + "processors": "", + "groups": ";Touch", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ee3d0cd2-254e-47a7-a8cb-bc94d9658c54", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8255d333-5683-4943-a58a-ccb207ff1dce", + "path": "/{PrimaryAction}", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3c1c7f0-bd20-4ee7-a0f1-899b24bca6d7", + "path": "/enter", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Attack", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "cbac6039-9c09-46a1-b5f2-4e5124ccb5ed", + "path": "/2", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e15ca19d-e649-4852-97d5-7fe8ccc44e94", + "path": "/dpad/right", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Next", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "f2e9ba44-c423-42a7-ad56-f20975884794", + "path": "/leftShift", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8cbb2f4b-a784-49cc-8d5e-c010b8c7f4e6", + "path": "/leftStickPress", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d8bf24bf-3f2f-4160-a97c-38ec1eb520ba", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Sprint", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "eb40bb66-4559-4dfa-9a2f-820438abb426", + "path": "/space", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "daba33a1-ad0c-4742-a909-43ad1cdfbeb6", + "path": "/buttonSouth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "603f3daf-40bd-4854-8724-93e8017f59e3", + "path": "/secondaryButton", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1534dc16-a6aa-499d-9c3a-22b47347b52a", + "path": "/1", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "25060bbd-a3a6-476e-8fba-45ae484aad05", + "path": "/dpad/left", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Previous", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1c04ea5f-b012-41d1-a6f7-02e963b52893", + "path": "/e", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "b3f66d0b-7751-423f-908b-a11c5bd95930", + "path": "/buttonNorth", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4f4649ac-64a8-4a73-af11-b3faef356a4d", + "path": "/buttonEast", + "interactions": "", + "processors": "", + "groups": "Gamepad", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "36e52cba-0905-478e-a818-f4bfcb9f3b9a", + "path": "/c", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + } + ] + }, + { + "name": "UI", + "id": "272f6d14-89ba-496f-b7ff-215263d3219f", + "actions": [ + { + "name": "Navigate", + "type": "PassThrough", + "id": "c95b2375-e6d9-4b88-9c4c-c5e76515df4b", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Submit", + "type": "Button", + "id": "7607c7b6-cd76-4816-beef-bd0341cfe950", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Cancel", + "type": "Button", + "id": "15cef263-9014-4fd5-94d9-4e4a6234a6ef", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Point", + "type": "PassThrough", + "id": "32b35790-4ed0-4e9a-aa41-69ac6d629449", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Click", + "type": "PassThrough", + "id": "3c7022bf-7922-4f7c-a998-c437916075ad", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "RightClick", + "type": "PassThrough", + "id": "44b200b1-1557-4083-816c-b22cbdf77ddf", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "MiddleClick", + "type": "PassThrough", + "id": "dad70c86-b58c-4b17-88ad-f5e53adf419e", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "ScrollWheel", + "type": "PassThrough", + "id": "0489e84a-4833-4c40-bfae-cea84b696689", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDevicePosition", + "type": "PassThrough", + "id": "24908448-c609-4bc3-a128-ea258674378a", + "expectedControlType": "Vector3", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "TrackedDeviceOrientation", + "type": "PassThrough", + "id": "9caa3d8a-6b2f-4e8e-8bad-6ede561bd9be", + "expectedControlType": "Quaternion", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "Gamepad", + "id": "809f371f-c5e2-4e7a-83a1-d867598f40dd", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "14a5d6e8-4aaf-4119-a9ef-34b8c2c548bf", + "path": "/leftStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "9144cbe6-05e1-4687-a6d7-24f99d23dd81", + "path": "/rightStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2db08d65-c5fb-421b-983f-c71163608d67", + "path": "/leftStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "58748904-2ea9-4a80-8579-b500e6a76df8", + "path": "/rightStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "8ba04515-75aa-45de-966d-393d9bbd1c14", + "path": "/leftStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "712e721c-bdfb-4b23-a86c-a0d9fcfea921", + "path": "/rightStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "fcd248ae-a788-4676-a12e-f4d81205600b", + "path": "/leftStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "1f04d9bc-c50b-41a1-bfcc-afb75475ec20", + "path": "/rightStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "fb8277d4-c5cd-4663-9dc7-ee3f0b506d90", + "path": "/dpad", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "Joystick", + "id": "e25d9774-381c-4a61-b47c-7b6b299ad9f9", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "3db53b26-6601-41be-9887-63ac74e79d19", + "path": "/stick/up", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "0cb3e13e-3d90-4178-8ae6-d9c5501d653f", + "path": "/stick/down", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "0392d399-f6dd-4c82-8062-c1e9c0d34835", + "path": "/stick/left", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "942a66d9-d42f-43d6-8d70-ecb4ba5363bc", + "path": "/stick/right", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "Keyboard", + "id": "ff527021-f211-4c02-933e-5976594c46ed", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "563fbfdd-0f09-408d-aa75-8642c4f08ef0", + "path": "/w", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "eb480147-c587-4a33-85ed-eb0ab9942c43", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "2bf42165-60bc-42ca-8072-8c13ab40239b", + "path": "/s", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "85d264ad-e0a0-4565-b7ff-1a37edde51ac", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "74214943-c580-44e4-98eb-ad7eebe17902", + "path": "/a", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "cea9b045-a000-445b-95b8-0c171af70a3b", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "8607c725-d935-4808-84b1-8354e29bab63", + "path": "/d", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "4cda81dc-9edd-4e03-9d7c-a71a14345d0b", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "9e92bb26-7e3b-4ec4-b06b-3c8f8e498ddc", + "path": "*/{Submit}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Submit", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "82627dcc-3b13-4ba9-841d-e4b746d6553e", + "path": "*/{Cancel}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Cancel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c52c8e0b-8179-41d3-b8a1-d149033bbe86", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "e1394cbc-336e-44ce-9ea8-6007ed6193f7", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "5693e57a-238a-46ed-b5ae-e64e6e574302", + "path": "/touch*/position", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4faf7dc9-b979-4210-aa8c-e808e1ef89f5", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "8d66d5ba-88d7-48e6-b1cd-198bbfef7ace", + "path": "/tip", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "47c2a644-3ebc-4dae-a106-589b7ca75b59", + "path": "/touch*/press", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "bb9e6b34-44bf-4381-ac63-5aa15d19f677", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "38c99815-14ea-4617-8627-164d27641299", + "path": "/scroll", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "ScrollWheel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4c191405-5738-4d4b-a523-c6a301dbf754", + "path": "/rightButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "RightClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "24066f69-da47-44f3-a07e-0015fb02eb2e", + "path": "/middleButton", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "MiddleClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "7236c0d9-6ca3-47cf-a6ee-a97f5b59ea77", + "path": "/devicePosition", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDevicePosition", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "23e01e3a-f935-4948-8d8b-9bcac77714fb", + "path": "/deviceRotation", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "TrackedDeviceOrientation", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [ + { + "name": "Keyboard&Mouse", + "bindingGroup": "Keyboard&Mouse", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + }, + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Gamepad", + "bindingGroup": "Gamepad", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Touch", + "bindingGroup": "Touch", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Joystick", + "bindingGroup": "Joystick", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "XR", + "bindingGroup": "XR", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + } + ] +} \ No newline at end of file diff --git a/Assets/InputSystem_Actions.inputactions.meta b/Assets/InputSystem_Actions.inputactions.meta new file mode 100644 index 0000000..6b38b04 --- /dev/null +++ b/Assets/InputSystem_Actions.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 052faaac586de48259a63d0c4782560b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 0 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: diff --git a/Assets/Plugins.meta b/Assets/Plugins.meta new file mode 100644 index 0000000..98a5618 --- /dev/null +++ b/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c0135c9b9e95e1a41b89d4e3bed05fb6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Newtonsoft.Json.dll b/Assets/Plugins/Newtonsoft.Json.dll new file mode 100644 index 0000000..341d08f Binary files /dev/null and b/Assets/Plugins/Newtonsoft.Json.dll differ diff --git a/Assets/Plugins/Newtonsoft.Json.dll.meta b/Assets/Plugins/Newtonsoft.Json.dll.meta new file mode 100644 index 0000000..578e9c2 --- /dev/null +++ b/Assets/Plugins/Newtonsoft.Json.dll.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 86371939112254644a31e78df202d79c \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity.meta b/Assets/Plugins/StoicGooseUnity.meta new file mode 100644 index 0000000..d701a92 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9604fb0f1487b95488164f5dc29a00ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common.meta new file mode 100644 index 0000000..35f0f21 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e1e5391f68e92f4db7f61cf8ed9557e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes.meta new file mode 100644 index 0000000..e448015 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 70afb0cb69f156a4b877a6dd0462fa04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs new file mode 100644 index 0000000..ae8b0a0 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs @@ -0,0 +1,21 @@ +using System; + +namespace StoicGoose.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class BitDescriptionAttribute : Attribute + { + public string Description { get; set; } = string.Empty; + public int LowBit { get; set; } = -1; + public int HighBit { get; set; } = -1; + + public string BitString => LowBit != -1 ? $"B{LowBit}{(HighBit > LowBit ? $"-{HighBit}" : string.Empty)}: " : string.Empty; + + public BitDescriptionAttribute(string desc, int low = -1, int high = -1) + { + Description = desc; + LowBit = low; + HighBit = high; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs.meta new file mode 100644 index 0000000..3200b06 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/BitDescriptionAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d881068effe996b459fdd198b8e7b046 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs new file mode 100644 index 0000000..104658b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace StoicGoose.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class FormatAttribute : Attribute + { + public string Format { get; set; } = string.Empty; + public int Shift { get; set; } = 0; + + public FormatAttribute(string format, int shift = 0) + { + Format = format; + Shift = shift; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs.meta new file mode 100644 index 0000000..3a7ff48 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/FormatAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2e358d7d3a0a0dd4a835853c38de5b88 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs new file mode 100644 index 0000000..c774966 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace StoicGoose.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class PortAttribute : Attribute + { + public string Name { get; set; } = string.Empty; + public List Numbers { get; set; } = new(); + + public PortAttribute(string name, params ushort[] numbers) + { + Name = name; + Numbers.AddRange(numbers); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs.meta new file mode 100644 index 0000000..4f0df20 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Attributes/PortAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e622fd59969209c48842cc5f6951d34f \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing.meta new file mode 100644 index 0000000..f6c9961 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62a562265df1f9b41949fb0a0d5d4491 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs new file mode 100644 index 0000000..556a809 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Linq; + +namespace StoicGoose.Common.Drawing +{ + /* RGBA bitmap file format -- https://github.com/bzotto/rgba_bitmap + * ".rgba is the dumbest possible image interchange format, now available for your programming pleasure." + */ + + public class RgbaFile + { + const string expectedMagic = "RGBA"; + + public string MagicNumber { get; protected set; } + public uint Width { get; protected set; } + public uint Height { get; protected set; } + public byte[] PixelData { get; protected set; } + + public RgbaFile(string filename) : this(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { } + + public RgbaFile(Stream stream) + { + MagicNumber = ReadString(stream, 4); + Width = ReadUInt32(stream); + Height = ReadUInt32(stream); + PixelData = new byte[Width * Height * 4]; + stream.Read(PixelData); + } + + public RgbaFile(uint width, uint height, byte[] pixelData) + { + MagicNumber = expectedMagic; + Width = width; + Height = height; + PixelData = pixelData; + } + + public void Save(string filename) => Save(new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)); + + public void Save(Stream stream) + { + WriteString(stream, MagicNumber); + WriteUInt32(stream, Width); + WriteUInt32(stream, Height); + stream.Write(PixelData); + } + + private static string ReadString(Stream stream, int length) => new(Enumerable.Range(0, length).Select(_ => (char)stream.ReadByte()).ToArray()); + private static uint ReadUInt32(Stream stream) => (uint)(((stream.ReadByte() & 0xFF) << 24) | ((stream.ReadByte() & 0xFF) << 16) | ((stream.ReadByte() & 0xFF) << 8) | ((stream.ReadByte() & 0xFF) << 0)); + + private static void WriteString(Stream stream, string str) => Array.ForEach(str.ToCharArray(), (x) => stream.WriteByte((byte)x)); + private static void WriteUInt32(Stream stream, uint val) { stream.WriteByte((byte)((val >> 24) & 0xFF)); stream.WriteByte((byte)((val >> 16) & 0xFF)); stream.WriteByte((byte)((val >> 8) & 0xFF)); stream.WriteByte((byte)((val >> 0) & 0xFF)); } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs.meta new file mode 100644 index 0000000..53fab10 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Drawing/RgbaFile.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 319acc894b323fd4f90b8e025383be58 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions.meta new file mode 100644 index 0000000..c0129c1 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d8d552996c36ed1478421faa10628ce6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs new file mode 100644 index 0000000..f3359da --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs @@ -0,0 +1,20 @@ +using Newtonsoft.Json; + +namespace StoicGoose.Common.Extensions +{ + public static class ObjectExtensionMethods + { + /* https://dotnetcoretutorials.com/2020/09/09/cloning-objects-in-c-and-net-core/ */ + public static T Clone(this T source) + { + if (source is null) return default; + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source, new JsonSerializerSettings() + { + ReferenceLoopHandling = ReferenceLoopHandling.Ignore + }), new JsonSerializerSettings() + { + ObjectCreationHandling = ObjectCreationHandling.Replace + }); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs.meta new file mode 100644 index 0000000..63fc6a4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/ObjectExtensionMethods.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6e4fde992b04dbe42be66c0ea83bb7c1 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs new file mode 100644 index 0000000..3aafd2e --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs @@ -0,0 +1,31 @@ +using System.IO; + +using Newtonsoft.Json; + +namespace StoicGoose.Common.Extensions +{ + public static class SerializationExtensionMethods + { + public static void SerializeToFile(this object obj, string jsonFileName) + { + SerializeToFile(obj, jsonFileName, new JsonSerializerSettings() { Formatting = Formatting.Indented }); + } + + public static void SerializeToFile(this object obj, string jsonFileName, JsonSerializerSettings serializerSettings) + { + using var writer = new StreamWriter(jsonFileName); + writer.Write(JsonConvert.SerializeObject(obj, serializerSettings)); + } + + public static T DeserializeFromFile(this string jsonFileName) + { + using var reader = new StreamReader(jsonFileName); + return (T)JsonConvert.DeserializeObject(reader.ReadToEnd(), typeof(T), new JsonSerializerSettings() { Formatting = Formatting.Indented }); + } + + public static T DeserializeObject(this string jsonString) + { + return (T)JsonConvert.DeserializeObject(jsonString, typeof(T), new JsonSerializerSettings() { Formatting = Formatting.Indented }); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs.meta new file mode 100644 index 0000000..1f73c71 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/SerializationExtensionMethods.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 07c7fb2a5f53f2f4aaa60f1673087d9c \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs new file mode 100644 index 0000000..e58ac63 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace StoicGoose.Common.Extensions +{ + public static class StringExtensionMethods + { + /* Modified from https://stackoverflow.com/a/2641383 */ + public static List IndexOfAll(this string str, string value) + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("Search string is null or empty", nameof(value)); + + var idxs = new List(); + for (var i = 0; ; i += value.Length) + { + i = str.IndexOf(value, i); + if (i == -1) return idxs; + idxs.Add(i); + } + } + + public static string EnsureEndsWithPeriod(this string str) => str + (!str.EndsWith('.') ? "." : string.Empty); + + /* Regex via https://superuser.com/a/380778 */ + public static string RemoveAnsi(this string str) => Regex.Replace(str, @"\x1b\[[0-9;]*[mGKHF]", ""); + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs.meta new file mode 100644 index 0000000..d76f28a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Extensions/StringExtensionMethods.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: da7cb8ba3dd19cb4e96fedb8dd687ab0 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization.meta new file mode 100644 index 0000000..10622fa --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2df240a96bd839c46a5d441273339c11 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs new file mode 100644 index 0000000..09b815c --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs @@ -0,0 +1,37 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace StoicGoose.Common.Localization +{ + public static class Localizer + { + public static string FallbackCulture { get; set; } = "en"; + + static JObject source = default; + + public static void Initialize(string jsonData) => source = JsonConvert.DeserializeObject(jsonData) as JObject; + + public static CultureInfo[] GetSupportedLanguages() => source?.Children().Select(x => new CultureInfo((x as JProperty).Name)).ToArray() ?? Array.Empty(); + + private static JToken GetToken(string path) => source?.SelectToken($"{CultureInfo.CurrentUICulture.TwoLetterISOLanguageName}.{path}") ?? source?.SelectToken($"{FallbackCulture}.{path}"); + public static string GetString(string path) => GetToken(path)?.Value() ?? path[(path.LastIndexOf('.') + 1)..]; + public static string GetString(string path, object parameters) + { + var result = GetString(path); + var properties = parameters.GetType().GetProperties(); + foreach (Match match in Regex.Matches(result, @"{(?[^}:]*):*(?[^}]*)}").Where(x => x.Success)) + { + var property = properties.First(x => x.Name == match.Groups["param"].Value); + var format = match.Groups["format"].Value; + var formattedValue = string.IsNullOrEmpty(format) ? $"{property.GetValue(parameters)}" : string.Format($"{{0:{format}}}", property.GetValue(parameters)); + result = result.Replace(match.Value, formattedValue); + } + return result; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs.meta new file mode 100644 index 0000000..1125405 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Localization/Localizer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e82b9629c32ff9f46bfd29ee8db43083 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL.meta new file mode 100644 index 0000000..08b6b34 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 574b4bdd297790146bf92464ada13031 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Buffer.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Buffer.cs new file mode 100644 index 0000000..0c6e4d4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Buffer.cs @@ -0,0 +1,89 @@ +using System; +using System.Runtime.InteropServices; + +using OpenTK.Graphics.OpenGL4; + +using StoicGoose.Common.OpenGL.Vertices; + +namespace StoicGoose.Common.OpenGL +{ + public sealed class Buffer : IDisposable + { + internal readonly Type dataType = default; + internal readonly BufferTarget bufferTarget = 0; + internal readonly BufferUsageHint bufferUsageHint = 0; + + internal readonly int handle = GL.GenBuffer(); + internal readonly int sizeInBytes = 0; + internal int count = 0; + + public Buffer(Type type, BufferTarget target, BufferUsageHint usage) + { + dataType = type; + bufferTarget = target; + bufferUsageHint = usage; + + sizeInBytes = Marshal.SizeOf(dataType); + } + + ~Buffer() + { + Dispose(); + } + + public void Dispose() + { + if (GL.IsBuffer(handle)) + GL.DeleteBuffer(handle); + + GC.SuppressFinalize(this); + } + + public static Buffer CreateBuffer(BufferTarget target, BufferUsageHint usage) where T : struct => new(typeof(T), target, usage); + public static Buffer CreateVertexBuffer(BufferUsageHint usage) where T : struct, IVertexStruct => CreateBuffer(BufferTarget.ArrayBuffer, usage); + public static Buffer CreateIndexBuffer(BufferUsageHint usage) where T : struct, IConvertible => CreateBuffer(BufferTarget.ElementArrayBuffer, usage); + + public void Bind() + { + GL.BindBuffer(bufferTarget, handle); + } + + public void Update(T[] data) where T : struct + { + if (dataType != typeof(T)) + throw new Exception("Type mismatch on buffer update"); + + if (data != null) + { + Bind(); + + if (data.Length == count) + GL.BufferSubData(bufferTarget, IntPtr.Zero, new IntPtr(count * sizeInBytes), data); + else + { + count = data.Length; + GL.BufferData(bufferTarget, new IntPtr(count * sizeInBytes), data, bufferUsageHint); + } + } + } + + public void Update(IntPtr data, int size) where T : struct + { + if (dataType != typeof(T)) + throw new Exception("Type mismatch on buffer update"); + + if (data != IntPtr.Zero) + { + Bind(); + + if (size == count) + GL.BufferSubData(bufferTarget, IntPtr.Zero, new IntPtr(count * sizeInBytes), data); + else + { + count = size; + GL.BufferData(bufferTarget, new IntPtr(count * sizeInBytes), data, bufferUsageHint); + } + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Buffer.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Buffer.cs.meta new file mode 100644 index 0000000..aaf40d3 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Buffer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 758af90e896ed334daa4b2c0b1ab907e \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/ContextInfo.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/ContextInfo.cs new file mode 100644 index 0000000..bea7029 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/ContextInfo.cs @@ -0,0 +1,30 @@ +using System.Linq; + +using OpenTK.Graphics.OpenGL4; + +using StoicGoose.Common.Utilities; + +namespace StoicGoose.Common.OpenGL +{ + public static class ContextInfo + { + public static string GLRenderer { get; } = GL.GetString(StringName.Renderer); + public static string GLShadingLanguageVersion { get; } = GL.GetString(StringName.ShadingLanguageVersion); + public static string GLVendor { get; } = GL.GetString(StringName.Vendor); + public static string GLVersion { get; } = GL.GetString(StringName.Version); + public static string[] GLExtensions { get; } = new string[GL.GetInteger(GetPName.NumExtensions)].Select((x, i) => x = GL.GetString(StringNameIndexed.Extensions, i)).ToArray(); + + public static void WriteToLog(object source, bool withExtensions = false) + { + Log.WriteEvent(LogSeverity.Debug, source, "OpenGL context:"); + Log.WriteEvent(LogSeverity.Debug, source, $"- Renderer: {GLRenderer}"); + Log.WriteEvent(LogSeverity.Debug, source, $"- Vendor: {GLVendor}"); + Log.WriteEvent(LogSeverity.Debug, source, $"- Version: {GLVersion}"); + Log.WriteEvent(LogSeverity.Debug, source, $"- GLSL version: {GLShadingLanguageVersion}"); + Log.WriteEvent(LogSeverity.Debug, source, $"- {GLExtensions.Length} extension(s) supported."); + if (withExtensions) + foreach (var extension in GLExtensions) + Log.WriteEvent(LogSeverity.Debug, source, $" {extension}"); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/ContextInfo.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/ContextInfo.cs.meta new file mode 100644 index 0000000..e09b9c9 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/ContextInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 75f627f66f93bc941b7f2317eb530132 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders.meta new file mode 100644 index 0000000..a2270a9 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d26ef25f71ffd7a44aee2c51ca6f86e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles.meta new file mode 100644 index 0000000..27f19ca --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3875a4162fb861b4eaa9afae91a79970 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles/BundleManifest.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles/BundleManifest.cs new file mode 100644 index 0000000..6a0d5ae --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles/BundleManifest.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace StoicGoose.Common.OpenGL.Shaders.Bundles +{ + public enum FilterMode { Linear, Nearest } + + public enum WrapMode { Repeat, Edge, Border, Mirror } + + public class BundleManifest + { + [JsonConverter(typeof(StringEnumConverter))] + public FilterMode Filter { get; set; } = FilterMode.Linear; + [JsonConverter(typeof(StringEnumConverter))] + public WrapMode Wrap { get; set; } = WrapMode.Repeat; + public int Samplers { get; set; } = 3; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles/BundleManifest.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles/BundleManifest.cs.meta new file mode 100644 index 0000000..eda8780 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Bundles/BundleManifest.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d09910e9ec835b4499af6123b16a840a \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Program.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Program.cs new file mode 100644 index 0000000..faf7713 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Program.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; + +using OpenTK.Graphics.OpenGL4; + +namespace StoicGoose.Common.OpenGL.Shaders +{ + public sealed class Program : IDisposable + { + public int Handle { get; } = GL.CreateProgram(); + + readonly Dictionary uniformLocations = new(); + + bool disposed = false; + + public Program(params int[] shaders) + { + foreach (var shader in shaders) GL.AttachShader(Handle, shader); + GL.LinkProgram(Handle); + + GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status); + if (status != 1) + { + GL.GetProgramInfoLog(Handle, out string info); + GL.DeleteProgram(Handle); + throw new Exception($"Program link failed:\n{info}"); + } + + foreach (var shader in shaders) + { + GL.DetachShader(Handle, shader); + GL.DeleteShader(shader); + } + + GL.UseProgram(0); + } + + ~Program() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + if (GL.IsProgram(Handle)) + GL.DeleteProgram(Handle); + } + + disposed = true; + } + + public void Bind() + { + GL.UseProgram(Handle); + } + + public int GetUniformLocation(string name) + { + if (!uniformLocations.ContainsKey(name)) + { + var location = GL.GetUniformLocation(Handle, name); + if (location != -1) uniformLocations[name] = location; + return location; + } + else + return uniformLocations[name]; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Program.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Program.cs.meta new file mode 100644 index 0000000..c867a70 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/Program.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 178551683b089fd41bbc20f82964d581 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/ShaderFactory.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/ShaderFactory.cs new file mode 100644 index 0000000..0fd02cc --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/ShaderFactory.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; + +using OpenTK.Graphics.OpenGL4; + +namespace StoicGoose.Common.OpenGL.Shaders +{ + public static class ShaderFactory + { + public static int FromSource(ShaderType shaderType, params string[] shaderSource) + { + shaderSource = Sanitize(shaderSource); + + int handle = GL.CreateShader(shaderType); + GL.ShaderSource(handle, shaderSource.Length, shaderSource, (int[])null); + GL.CompileShader(handle); + + GL.GetShader(handle, ShaderParameter.CompileStatus, out int status); + if (status != 1) + { + GL.GetShaderInfoLog(handle, out string info); + GL.DeleteShader(handle); + throw new Exception($"{shaderType} compile failed:\n{info}"); + } + + return handle; + } + + private static string[] Sanitize(string[] shaderSource) + { + return shaderSource.Where(x => !string.IsNullOrEmpty(x)).Select(z => string.Concat(z, Environment.NewLine)).ToArray(); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/ShaderFactory.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/ShaderFactory.cs.meta new file mode 100644 index 0000000..59bb161 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Shaders/ShaderFactory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d34d8d41a7c062747ba60af3cca96bdd \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/State.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/State.cs new file mode 100644 index 0000000..2ebf77b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/State.cs @@ -0,0 +1,109 @@ +using System; +using System.Drawing; +using System.Runtime.CompilerServices; + +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL +{ + public class State + { + static State lastState = default; + + bool depthTestEnable = true, blendEnable = true, cullFaceEnable = true, scissorTestEnable = false; + BlendingFactor blendSource = BlendingFactor.SrcAlpha, blendDest = BlendingFactor.OneMinusSrcAlpha; + CullFaceMode cullFaceMode = CullFaceMode.Back; + Vector4i scissorBox = Vector4i.Zero; + Color clearColor = Color.Black; + Vector4i viewport = Vector4i.Zero; + + public void Enable(EnableCap cap) => SetCap(cap, true); + public void Disable(EnableCap cap) => SetCap(cap, false); + + public void SetBlending(BlendingFactor source, BlendingFactor dest) { blendSource = source; blendDest = dest; } + public void SetCullFace(CullFaceMode mode) => cullFaceMode = mode; + public void SetScissor(Vector4i box) => scissorBox = box; + public void SetScissor(int x, int y, int width, int height) => scissorBox = new(x, y, width, height); + public void SetClearColor(Color color) => clearColor = color; + public void SetViewport(Vector4i vp) => viewport = vp; + public void SetViewport(int x, int y, int width, int height) => viewport = new(x, y, width, height); + + private void SetCap(EnableCap cap, bool value) + { + switch (cap) + { + case EnableCap.DepthTest: depthTestEnable = value; break; + case EnableCap.Blend: blendEnable = value; break; + case EnableCap.CullFace: cullFaceEnable = value; break; + case EnableCap.ScissorTest: scissorTestEnable = value; break; + default: throw new StateException($"{cap} not implemented"); + } + } + + private bool GetCap(EnableCap cap) + { + return cap switch + { + EnableCap.DepthTest => depthTestEnable, + EnableCap.Blend => blendEnable, + EnableCap.CullFace => cullFaceEnable, + EnableCap.ScissorTest => scissorTestEnable, + _ => throw new StateException($"{cap} not implemented"), + }; + } + + public void Submit() + { + if (lastState?.clearColor != clearColor) + GL.ClearColor(clearColor); + + SubmitState(EnableCap.DepthTest, depthTestEnable); + SubmitState(EnableCap.Blend, blendEnable); + SubmitState(EnableCap.CullFace, cullFaceEnable); + SubmitState(EnableCap.ScissorTest, scissorTestEnable); + + if (lastState?.viewport != viewport) + GL.Viewport(viewport.X, viewport.Y, viewport.Z, viewport.W); + + lastState = (State)MemberwiseClone(); + } + + private void SubmitState(EnableCap cap, bool value) + { + var enableChanged = lastState?.GetCap(cap) != GetCap(cap); + + if (value) + { + if (enableChanged) GL.Enable(cap); + + switch (cap) + { + case EnableCap.Blend: + if (lastState?.blendSource != blendSource || lastState?.blendDest != blendDest) + GL.BlendFunc(blendSource, blendDest); + break; + + case EnableCap.CullFace: + if (lastState?.cullFaceMode != cullFaceMode) + GL.CullFace(cullFaceMode); + break; + + case EnableCap.ScissorTest: + if (lastState?.scissorBox != scissorBox) + GL.Scissor(scissorBox.X, scissorBox.Y, scissorBox.Z, scissorBox.W); + break; + } + } + else + { + if (enableChanged) GL.Disable(cap); + } + } + } + + public class StateException : Exception + { + public StateException(string message, [CallerMemberName] string callerName = "") : base($"In {callerName}: {message}") { } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/State.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/State.cs.meta new file mode 100644 index 0000000..3d65ff6 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/State.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 792e396ff7046af4eb6149dbaad83660 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Texture.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Texture.cs new file mode 100644 index 0000000..aa0bd14 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Texture.cs @@ -0,0 +1,169 @@ +using System; +using System.Runtime.InteropServices; + +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +using StoicGoose.Common.Drawing; + +namespace StoicGoose.Common.OpenGL +{ + public sealed class Texture : IDisposable + { + const TextureMinFilter defaultMinFilter = TextureMinFilter.Nearest; + const TextureMagFilter defaultMagFilter = TextureMagFilter.Nearest; + const TextureWrapMode defaultWrapModeS = TextureWrapMode.Repeat; + const TextureWrapMode defaultWrapModeT = TextureWrapMode.Repeat; + + public int Handle { get; } = GL.GenTexture(); + public Vector2i Size { get; private set; } = Vector2i.Zero; + + byte[] pixelData = default; + bool isDirty = false; + + bool disposed = false; + + public Texture(int width, int height) : this(width, height, 255, 255, 255, 255) { } + + public Texture(int width, int height, byte r, byte g, byte b, byte a) + { + Size = new Vector2i(width, height); + var data = new byte[width * height * 4]; + for (var i = 0; i < data.Length; i += 4) + { + data[i + 0] = r; + data[i + 1] = g; + data[i + 2] = b; + data[i + 3] = a; + } + SetInitialTexImage(data); + } + + public Texture(RgbaFile rgbaFile) + { + Size = new Vector2i((int)rgbaFile.Width, (int)rgbaFile.Height); + SetInitialTexImage(rgbaFile.PixelData); + } + + public Texture(int width, int height, byte[] data) + { + Size = new Vector2i(width, height); + SetInitialTexImage(data); + } + + public Texture(int width, int height, IntPtr data) + { + Size = new Vector2i(width, height); + SetInitialTexImage(data); + } + + ~Texture() + { + Dispose(false); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + if (GL.IsTexture(Handle)) + GL.DeleteTexture(Handle); + } + + disposed = true; + } + + private void SetInitialTexImage(byte[] data) + { + var handle = GCHandle.Alloc(data, GCHandleType.Pinned); + var pointer = handle.AddrOfPinnedObject(); + SetInitialTexImage(pointer); + handle.Free(); + } + + private void SetInitialTexImage(IntPtr pixels) + { + ChangeTextureParams(() => + { + GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, Size.X, Size.Y, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pixels); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)defaultMinFilter); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)defaultMagFilter); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)defaultWrapModeS); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)defaultWrapModeT); + }); + } + + public void SetTextureFilter(TextureMinFilter textureMinFilter, TextureMagFilter textureMagFilter) + { + ChangeTextureParams(() => + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)textureMinFilter); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)textureMagFilter); + }); + } + + public void SetTextureWrapMode(TextureWrapMode textureWrapModeS, TextureWrapMode textureWrapModeT) + { + ChangeTextureParams(() => + { + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)textureWrapModeS); + GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)textureWrapModeT); + }); + } + + private void ChangeTextureParams(Action action) + { + var lastTextureSet = GL.GetInteger(GetPName.Texture2D); + if (Handle != lastTextureSet) GL.BindTexture(TextureTarget.Texture2D, Handle); + action?.Invoke(); + GL.BindTexture(TextureTarget.Texture2D, lastTextureSet); + } + + public void Bind() + { + Bind(0); + } + + public void Bind(int textureUnit) + { + GL.ActiveTexture(TextureUnit.Texture0 + textureUnit); + GL.BindTexture(TextureTarget.Texture2D, Handle); + + if (isDirty) + { + GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Size.X, Size.Y, PixelFormat.Rgba, PixelType.UnsignedByte, pixelData); + isDirty = false; + } + } + + public void Update(byte[] data) + { + isDirty = true; + pixelData = data; + } + + public void Fill(byte r, byte g, byte b, byte a) + { + isDirty = true; + + var data = new byte[Size.X * Size.Y * 4]; + for (var i = 0; i < data.Length; i += 4) + { + data[i + 0] = r; + data[i + 1] = g; + data[i + 2] = b; + data[i + 3] = a; + } + pixelData = data; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Texture.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Texture.cs.meta new file mode 100644 index 0000000..5fd55ae --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Texture.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e8e182c0d8fab6345820f6479ae9d179 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms.meta new file mode 100644 index 0000000..fba094f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a45b95df3f0085f46bbfafbc4238c75e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Color4Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Color4Uniform.cs new file mode 100644 index 0000000..db6e6c4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Color4Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Color4Uniform : GenericUniform + { + public Color4Uniform(string name) : this(name, Color4.White) { } + public Color4Uniform(string name, Color4 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform4(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Color4Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Color4Uniform.cs.meta new file mode 100644 index 0000000..57a13a0 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Color4Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9c1a6e5abf4fb164680ad3838edd5d0a \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/FloatUniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/FloatUniform.cs new file mode 100644 index 0000000..366ab5a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/FloatUniform.cs @@ -0,0 +1,15 @@ +using OpenTK.Graphics.OpenGL4; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class FloatUniform : GenericUniform + { + public FloatUniform(string name) : this(name, 0.0f) { } + public FloatUniform(string name, float value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform1(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/FloatUniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/FloatUniform.cs.meta new file mode 100644 index 0000000..8a6e0d9 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/FloatUniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: def2e09bbdbff364a98af688ebd96f48 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/GenericUniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/GenericUniform.cs new file mode 100644 index 0000000..96d04db --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/GenericUniform.cs @@ -0,0 +1,33 @@ +using ShaderProgram = StoicGoose.Common.OpenGL.Shaders.Program; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public abstract class GenericUniform + { + protected readonly string name; + protected T value; + + public string Name => name; + public T Value + { + get => value; + set => this.value = value; + } + + public GenericUniform(string name) : this(name, default) { } + + public GenericUniform(string name, T value) + { + this.name = name; + this.value = value; + } + + public void SubmitToProgram(ShaderProgram shaderProgram) + { + var location = shaderProgram.GetUniformLocation(name); + if (location != -1) SubmitUniform(location); + } + + protected abstract void SubmitUniform(int location); + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/GenericUniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/GenericUniform.cs.meta new file mode 100644 index 0000000..d139d72 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/GenericUniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f6af09d6382461c4ab65e947b2f2fb2b \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/IntUniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/IntUniform.cs new file mode 100644 index 0000000..b994f39 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/IntUniform.cs @@ -0,0 +1,15 @@ +using OpenTK.Graphics.OpenGL4; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class IntUniform : GenericUniform + { + public IntUniform(string name) : this(name, 0) { } + public IntUniform(string name, int value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform1(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/IntUniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/IntUniform.cs.meta new file mode 100644 index 0000000..569a9df --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/IntUniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fef7b73ffc9a5004390704d47e96f3d4 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix2Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix2Uniform.cs new file mode 100644 index 0000000..9e49c22 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix2Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Matrix2Uniform : GenericUniform + { + public Matrix2Uniform(string name) : this(name, Matrix2.Identity) { } + public Matrix2Uniform(string name, Matrix2 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.UniformMatrix2(location, false, ref value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix2Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix2Uniform.cs.meta new file mode 100644 index 0000000..bdbb00b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix2Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d4f7ad547458c8d43ab14ab22118f93d \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix3Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix3Uniform.cs new file mode 100644 index 0000000..15dbb01 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix3Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Matrix3Uniform : GenericUniform + { + public Matrix3Uniform(string name) : this(name, Matrix3.Identity) { } + public Matrix3Uniform(string name, Matrix3 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.UniformMatrix3(location, false, ref value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix3Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix3Uniform.cs.meta new file mode 100644 index 0000000..c24fd37 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix3Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 92c5ec8dd24a17346ae45748b1a0178f \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix4Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix4Uniform.cs new file mode 100644 index 0000000..88e95da --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix4Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Matrix4Uniform : GenericUniform + { + public Matrix4Uniform(string name) : this(name, Matrix4.Identity) { } + public Matrix4Uniform(string name, Matrix4 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.UniformMatrix4(location, false, ref value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix4Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix4Uniform.cs.meta new file mode 100644 index 0000000..4900392 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Matrix4Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 35f3ae40f4eab43439ede677f7faa3ec \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/UintUniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/UintUniform.cs new file mode 100644 index 0000000..97155d2 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/UintUniform.cs @@ -0,0 +1,15 @@ +using OpenTK.Graphics.OpenGL4; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class UintUniform : GenericUniform + { + public UintUniform(string name) : this(name, 0) { } + public UintUniform(string name, uint value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform1(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/UintUniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/UintUniform.cs.meta new file mode 100644 index 0000000..d1fd030 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/UintUniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7f8ad0c178d3da54590b050a192b3278 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector2Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector2Uniform.cs new file mode 100644 index 0000000..448837d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector2Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Vector2Uniform : GenericUniform + { + public Vector2Uniform(string name) : this(name, Vector2.Zero) { } + public Vector2Uniform(string name, Vector2 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform2(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector2Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector2Uniform.cs.meta new file mode 100644 index 0000000..0b635e9 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector2Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 20ad22abc90ef954b8cce3348210bbb4 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector3Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector3Uniform.cs new file mode 100644 index 0000000..308c3ef --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector3Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Vector3Uniform : GenericUniform + { + public Vector3Uniform(string name) : this(name, Vector3.Zero) { } + public Vector3Uniform(string name, Vector3 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform3(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector3Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector3Uniform.cs.meta new file mode 100644 index 0000000..a5a9791 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector3Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fbb5a6d3f29b9a44da578e67ac4e4100 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector4Uniform.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector4Uniform.cs new file mode 100644 index 0000000..6c27b02 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector4Uniform.cs @@ -0,0 +1,16 @@ +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Uniforms +{ + public sealed class Vector4Uniform : GenericUniform + { + public Vector4Uniform(string name) : this(name, Vector4.Zero) { } + public Vector4Uniform(string name, Vector4 value) : base(name, value) { } + + protected override void SubmitUniform(int location) + { + GL.Uniform4(location, value); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector4Uniform.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector4Uniform.cs.meta new file mode 100644 index 0000000..f8e2fe6 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Uniforms/Vector4Uniform.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bf80a2f2d6662894793579d648d7bdce \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices.meta new file mode 100644 index 0000000..ef0f750 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65357137316d75b4f871a534339a4892 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/IVertexStruct.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/IVertexStruct.cs new file mode 100644 index 0000000..5684a9e --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/IVertexStruct.cs @@ -0,0 +1,4 @@ +namespace StoicGoose.Common.OpenGL.Vertices +{ + public interface IVertexStruct { } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/IVertexStruct.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/IVertexStruct.cs.meta new file mode 100644 index 0000000..89b9413 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/IVertexStruct.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d7f1ee3812c5583429ba5077b21aa114 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/Vertex.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/Vertex.cs new file mode 100644 index 0000000..4f093dc --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/Vertex.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; + +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Vertices +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct Vertex : IVertexStruct + { + public Vector2 Position; + public Vector2 TexCoord; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/Vertex.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/Vertex.cs.meta new file mode 100644 index 0000000..a85049c --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/Vertex.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b58b069763f795d42a28445d38bf14ca \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexArray.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexArray.cs new file mode 100644 index 0000000..a0fb75b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexArray.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; + +using OpenTK.Graphics.OpenGL4; +using OpenTK.Mathematics; + +namespace StoicGoose.Common.OpenGL.Vertices +{ + public sealed class VertexArray : IDisposable + { + static readonly Dictionary methodTypeIdentifier = new() + { + { typeof(sbyte), VertexAttribMethodType.Integer }, + { typeof(byte), VertexAttribMethodType.Integer }, + { typeof(short), VertexAttribMethodType.Integer }, + { typeof(ushort), VertexAttribMethodType.Integer }, + { typeof(int), VertexAttribMethodType.Integer }, + { typeof(uint), VertexAttribMethodType.Integer }, + { typeof(float), VertexAttribMethodType.Pointer }, + { typeof(double), VertexAttribMethodType.Pointer }, + { typeof(Color4), VertexAttribMethodType.Pointer }, + { typeof(Vector2), VertexAttribMethodType.Pointer }, + { typeof(Vector3), VertexAttribMethodType.Pointer }, + { typeof(Vector4), VertexAttribMethodType.Pointer }, + { typeof(Vector2d), VertexAttribMethodType.Pointer }, + { typeof(Vector3d), VertexAttribMethodType.Pointer }, + { typeof(Vector4d), VertexAttribMethodType.Pointer }, + { typeof(Vector2i), VertexAttribMethodType.Integer }, + { typeof(Vector3i), VertexAttribMethodType.Integer }, + { typeof(Vector4i), VertexAttribMethodType.Integer } + }; + + static readonly Dictionary pointerTypeTranslator = new() + { + { typeof(sbyte), VertexAttribPointerType.Byte }, + { typeof(byte), VertexAttribPointerType.UnsignedByte }, + { typeof(short), VertexAttribPointerType.Short }, + { typeof(ushort), VertexAttribPointerType.UnsignedShort }, + { typeof(int), VertexAttribPointerType.Int }, + { typeof(uint), VertexAttribPointerType.UnsignedInt }, + { typeof(float), VertexAttribPointerType.Float }, + { typeof(double), VertexAttribPointerType.Double }, + { typeof(Color4), VertexAttribPointerType.Float }, + { typeof(Vector2), VertexAttribPointerType.Float }, + { typeof(Vector3), VertexAttribPointerType.Float }, + { typeof(Vector4), VertexAttribPointerType.Float }, + { typeof(Vector2d), VertexAttribPointerType.Double }, + { typeof(Vector3d), VertexAttribPointerType.Double }, + { typeof(Vector4d), VertexAttribPointerType.Double }, + { typeof(Vector2i), VertexAttribPointerType.Int }, + { typeof(Vector3i), VertexAttribPointerType.Int }, + { typeof(Vector4i), VertexAttribPointerType.Int } + }; + + static readonly Dictionary integerTypeTranslator = new() + { + { typeof(sbyte), VertexAttribIntegerType.Byte }, + { typeof(byte), VertexAttribIntegerType.UnsignedByte }, + { typeof(short), VertexAttribIntegerType.Short }, + { typeof(ushort), VertexAttribIntegerType.UnsignedShort }, + { typeof(int), VertexAttribIntegerType.Int }, + { typeof(uint), VertexAttribIntegerType.UnsignedInt }, + { typeof(Vector2i), VertexAttribIntegerType.Int }, + { typeof(Vector3i), VertexAttribIntegerType.Int }, + { typeof(Vector4i), VertexAttribIntegerType.Int } + }; + + static readonly Dictionary drawElementsTypeTranslator = new() + { + { typeof(byte), DrawElementsType.UnsignedByte }, + { typeof(ushort), DrawElementsType.UnsignedShort }, + { typeof(uint), DrawElementsType.UnsignedInt } + }; + + enum VertexAttribMethodType { Pointer, Integer } + + internal readonly Buffer vertexBuffer = default, indexBuffer = default; + + internal readonly int handle = 0; + internal readonly VertexAttribute[] attributes = default; + + public int NumVertices => vertexBuffer.count; + public int NumIndices => indexBuffer != null ? indexBuffer.count : 0; + + public VertexArray(Buffer vtxBuffer) : this(vtxBuffer, null) { } + + public VertexArray(Buffer vtxBuffer, Buffer idxBuffer) + { + vertexBuffer = vtxBuffer; + indexBuffer = idxBuffer; + + handle = GL.GenVertexArray(); + attributes = DeconstructVertexLayout(vtxBuffer.dataType); + + GL.BindVertexArray(handle); + vertexBuffer.Bind(); + + for (var i = 0; i < attributes.Length; i++) + { + var attribute = attributes[i]; + + if (!methodTypeIdentifier.ContainsKey(attribute.Type)) continue; + + GL.EnableVertexAttribArray(i); + switch (methodTypeIdentifier[attribute.Type]) + { + case VertexAttribMethodType.Pointer: + GL.VertexAttribPointer(i, attribute.Size, GetVertexAttribPointerType(attribute.Type), false, vtxBuffer.sizeInBytes, new IntPtr(attribute.Offset)); + break; + case VertexAttribMethodType.Integer: + GL.VertexAttribIPointer(i, attribute.Size, GetVertexAttribIntegerType(attribute.Type), vtxBuffer.sizeInBytes, new IntPtr(attribute.Offset)); + break; + } + } + + indexBuffer?.Bind(); + + GL.BindVertexArray(0); + } + + ~VertexArray() + { + Dispose(); + } + + public void Dispose() + { + if (GL.IsVertexArray(handle)) + GL.DeleteVertexArray(handle); + + vertexBuffer?.Dispose(); + indexBuffer?.Dispose(); + + GC.SuppressFinalize(this); + } + + private static VertexAttribute[] DeconstructVertexLayout(Type vertexType) + { + var attributes = new List(); + + foreach (var field in vertexType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (!field.FieldType.IsArray) + { + var fieldSize = Marshal.SizeOf(field.FieldType); + + if (field.FieldType.IsValueType && !field.FieldType.IsEnum) + { + var structFields = field.FieldType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (structFields == null || structFields.Length < 1 || structFields.Length > 4) throw new Exception("Invalid number of fields in struct"); + fieldSize = structFields.Length; + } + + attributes.Add(new VertexAttribute() + { + Type = field.FieldType, + Size = fieldSize, + Offset = Marshal.OffsetOf(vertexType, field.Name).ToInt32(), + Name = field.Name + }); + } + else + throw new NotImplementedException("GLSL arrays not implemented"); + } + + return attributes.ToArray(); + } + + private static VertexAttribPointerType GetVertexAttribPointerType(Type type) + { + if (pointerTypeTranslator.ContainsKey(type)) + return pointerTypeTranslator[type]; + else + throw new ArgumentException("Unimplemented or unsupported vertex attribute pointer type"); + } + + private static VertexAttribIntegerType GetVertexAttribIntegerType(Type type) + { + if (integerTypeTranslator.ContainsKey(type)) + return integerTypeTranslator[type]; + else + throw new ArgumentException("Unimplemented or unsupported vertex attribute integer type"); + } + + private static DrawElementsType GetDrawElementsType(Type type) + { + if (drawElementsTypeTranslator.ContainsKey(type)) + return drawElementsTypeTranslator[type]; + else + throw new ArgumentException("Unsupported draw elements type"); + } + + public void Draw(PrimitiveType primitiveType) + { + GL.BindVertexArray(handle); + + if (indexBuffer != null) + GL.DrawElements(primitiveType, indexBuffer.count, GetDrawElementsType(indexBuffer.dataType), 0); + else + GL.DrawArrays(primitiveType, 0, vertexBuffer.count); + } + + public void DrawIndices(PrimitiveType primitiveType, int offset, int count) + { + if (indexBuffer == null) throw new NotImplementedException("Cannot use DrawIndices without an indexbuffer"); + + GL.BindVertexArray(handle); + GL.DrawElements(primitiveType, count, GetDrawElementsType(indexBuffer.dataType), offset * indexBuffer.sizeInBytes); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexArray.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexArray.cs.meta new file mode 100644 index 0000000..440291d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexArray.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c89413b44ed365f4f8abc8587da9ba94 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexAttribute.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexAttribute.cs new file mode 100644 index 0000000..d4960c7 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexAttribute.cs @@ -0,0 +1,12 @@ +using System; + +namespace StoicGoose.Common.OpenGL.Vertices +{ + public sealed class VertexAttribute + { + public Type Type { get; internal set; } = default; + public int Size { get; internal set; } = -1; + public int Offset { get; internal set; } = -1; + public string Name { get; internal set; } = string.Empty; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexAttribute.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexAttribute.cs.meta new file mode 100644 index 0000000..7909bd8 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/OpenGL/Vertices/VertexAttribute.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8d8f3e1419988e144b05f78cdc6c73b5 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities.meta new file mode 100644 index 0000000..2c0d21f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6d169728b1f850a4db4171c5dab2507c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs new file mode 100644 index 0000000..d928ac4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace StoicGoose.Common.Utilities +{ + public static class Ansi + { + public readonly static string Reset = "\x1B[0m"; + public readonly static string Black = "\x1B[30m"; + public readonly static string Red = "\x1B[31m"; + public readonly static string Green = "\x1B[32m"; + public readonly static string Yellow = "\x1B[33m"; + public readonly static string Blue = "\x1B[34m"; + public readonly static string Magenta = "\x1B[35m"; + public readonly static string Cyan = "\x1B[36m"; + public readonly static string White = "\x1B[37m"; + + public static string RGB(byte r, byte g, byte b) => $"\x1B[38;2;{r};{g};{b}m"; + + // Such a stupid gimmick... but hey, I like stupid gimmicks and I especially like making them, so whatever~ + public static string Gradient(string text, bool useHsl, params (byte r, byte g, byte b)[] colors) + { + var stepsPerColor = (int)Math.Round(text.Length / (colors.Length - 1f), MidpointRounding.AwayFromZero); + var steps = Math.Max(stepsPerColor * (colors.Length - 1), text.Length); + + List<(byte r, byte g, byte b)> gradient = new(); + + for (int i = 0, c = 0; i < steps; i += stepsPerColor, c++) + { + // TODO: this is a workaround for a out-of-range bug, but ugh, it's for a mere gimmick barely anyone will ever see, soooooo... whatever! + if (c + 1 >= colors.Length) c--; + + if (useHsl) + { + var (h1, s1, l1) = RgbToHsl(colors[c + 0].r, colors[c + 0].g, colors[c + 0].b); + var (h2, s2, l2) = RgbToHsl(colors[c + 1].r, colors[c + 1].g, colors[c + 1].b); + + for (var j = 0; j < stepsPerColor; j++) + { + var by = Math.Clamp(j / 1f / ((stepsPerColor - 1) / 1f), 0f, 1f); + var (h, s, l) = Lerp(h1, s1, l1, h2, s2, l2, by); + gradient.Add(HslToRgb(h, s, l)); + } + } + else + { + var (r1, g1, b1) = (colors[c + 0].r / 255f, colors[c + 0].g / 255f, colors[c + 0].b / 255f); + var (r2, g2, b2) = (colors[c + 1].r / 255f, colors[c + 1].g / 255f, colors[c + 1].b / 255f); + + for (var j = 0; j < stepsPerColor; j++) + { + var by = Math.Clamp(j / 1f / ((stepsPerColor - 1) / 1f), 0f, 1f); + gradient.Add(((byte)(Lerp(r1, r2, by) * 255), (byte)(Lerp(g1, g2, by) * 255), (byte)(Lerp(b1, b2, by) * 255))); + } + } + } + + var builder = new StringBuilder(); + for (var i = 0; i < Math.Min(gradient.Count, text.Length); i++) + builder.Append($"{RGB(gradient[i].r, gradient[i].g, gradient[i].b)}{text[i]}"); + return builder.ToString(); + } + + private static float Lerp(float v1, float v2, float by) => v1 * (1f - by) + v2 * by; + private static (float h, float s, float l) Lerp(float h1, float s1, float l1, float h2, float s2, float l2, float by) => (Lerp(h1, h2, by) % 360f, Math.Clamp(Lerp(s1, s2, by), 0f, 1f), Math.Clamp(Lerp(l1, l2, by), 0f, 1f)); + + // http://www.easyrgb.com/en/math.php + private static (float h, float s, float l) RgbToHsl(byte red, byte green, byte blue) + { + float h = 0f, s, l; + + var r = red / 255f; + var g = green / 255f; + var b = blue / 255f; + + var min = Math.Min(Math.Min(r, g), b); + var max = Math.Max(Math.Max(r, g), b); + var deltaMax = max - min; + + l = (max + min) / 2f; + + if (deltaMax == 0) + { + h = 0; + s = 0; + } + else + { + if (l < 0.5f) s = deltaMax / (max + min); + else s = deltaMax / (2f - max - min); + + var deltaR = ((max - r) / 6f + deltaMax / 2f) / deltaMax; + var deltaG = ((max - g) / 6f + deltaMax / 2f) / deltaMax; + var deltaB = ((max - b) / 6f + deltaMax / 2f) / deltaMax; + + if (r == max) h = deltaB - deltaG; + else if (g == max) h = 1f / 3f + deltaR - deltaB; + else if (b == max) h = 2f / 3f + deltaG - deltaR; + + if (h < 0f) h++; + if (h > 1f) h--; + } + + return (h, s, l); + } + + // http://www.easyrgb.com/en/math.php + private static (byte r, byte g, byte b) HslToRgb(float hue, float saturation, float lightness) + { + byte r, g, b; + + if (saturation == 0f) + { + r = (byte)(lightness * 255); + g = (byte)(lightness * 255); + b = (byte)(lightness * 255); + } + else + { + float v1, v2; + + if (lightness < 0.5f) v2 = lightness * (1f + saturation); + else v2 = lightness + saturation - saturation * lightness; + + v1 = 2f * lightness - v2; + + r = (byte)(255 * HueToRgb(v1, v2, hue + 1f / 3f)); + g = (byte)(255 * HueToRgb(v1, v2, hue)); + b = (byte)(255 * HueToRgb(v1, v2, hue - 1f / 3f)); + } + + return (r, g, b); + } + + private static float HueToRgb(float v1, float v2, float vh) + { + if (vh < 0f) vh++; + if (vh > 1) vh--; + + if (6f * vh < 1f) return v1 + (v2 - v1) * 6f * vh; + if (2f * vh < 1f) return v2; + if (3f * vh < 2f) return v1 + (v2 - v1) * (2f / 3f - vh) * 6f; + return v1; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs.meta new file mode 100644 index 0000000..5bf3b21 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Ansi.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0f30cf7d655b21e49a24ff276bbc9861 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs new file mode 100644 index 0000000..e9031e1 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs @@ -0,0 +1,8 @@ +namespace StoicGoose.Common.Utilities +{ + public static class Bcd + { + public static int DecimalToBcd(int value) => ((value / 10) << 4) + (value % 10); + public static int BcdToDecimal(int value) => ((value >> 4) * 10) + value % 16; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs.meta new file mode 100644 index 0000000..959d47d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Bcd.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e71734276750fc04990a5d08f116ee5d \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs new file mode 100644 index 0000000..2254857 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs @@ -0,0 +1,15 @@ +namespace StoicGoose.Common.Utilities +{ + public static class BitHandling + { + public static void ChangeBit(ref byte value, int bit, bool state) + { + if (state) + value |= (byte)(1 << bit); + else + value &= (byte)~(1 << bit); + } + + public static bool IsBitSet(byte value, int bit) => (value & (1 << bit)) != 0; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs.meta new file mode 100644 index 0000000..e3d4641 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/BitHandling.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d00bd13e7a297b34683f7c739fc50d46 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs new file mode 100644 index 0000000..a835de9 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace StoicGoose.Common.Utilities +{ + public abstract class ConfigurationBase where T : class, new() + { + public static readonly Dictionary Defaults = default; + + static ConfigurationBase() + { + Defaults = GetDefaultValues(); + } + + private static Dictionary GetDefaultValues() + { + var dict = new Dictionary(); + var instance = new T(); + + foreach (var property in typeof(T).GetProperties().Where(x => x.CanWrite)) + { + var value = property.GetValue(instance); + if (value == null || (property.PropertyType == typeof(string) && string.IsNullOrEmpty(value as string))) continue; + dict.Add(property.Name, value); + } + + return dict; + } + + public void ResetToDefault(string name) + { + var property = GetType().GetProperty(name); + if (property == null) throw new ArgumentException($"Setting '{name}' not found in {GetType().Name}", nameof(name)); + property.SetValue(this, Defaults[name]); + } + } + + public static class ConfigurationBase + { + public static void CopyConfiguration(object source, object destination) + { + if (source == null) throw new ArgumentNullException(nameof(source), "Source cannot be null"); + if (destination == null) throw new ArgumentNullException(nameof(destination), "Destination cannot be null"); + + var sourceType = source.GetType(); + var destType = destination.GetType(); + + foreach (var sourceProperty in sourceType.GetProperties().Where(x => x.CanRead)) + { + var destProperty = destType.GetProperty(sourceProperty.Name); + if (destProperty == null || !destProperty.CanWrite || destProperty.GetSetMethod(true) == null || destProperty.GetSetMethod(true).IsPrivate || + destProperty.GetSetMethod(true).Attributes.HasFlag(System.Reflection.MethodAttributes.Static) || + !destProperty.PropertyType.IsAssignableFrom(sourceProperty.PropertyType)) + continue; + + var sourceValue = sourceProperty.GetValue(source, null); + var destValue = destProperty.GetValue(destination, null); + + if ((sourceProperty.PropertyType.BaseType.IsGenericType ? sourceProperty.PropertyType.BaseType.GetGenericTypeDefinition() : sourceProperty.PropertyType.BaseType) == typeof(ConfigurationBase<>)) + CopyConfiguration(sourceValue, destValue); + else + destProperty.SetValue(destination, sourceValue); + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs.meta new file mode 100644 index 0000000..0d0d669 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/ConfigurationBase.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 76e83b1a596480f48a7afe097d979b83 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs new file mode 100644 index 0000000..e7dbfb5 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs @@ -0,0 +1,82 @@ +using System; +using System.IO; + +namespace StoicGoose.Common.Utilities +{ + public static class Crc32 + { + static readonly uint[] crcTable; + static readonly uint crcPolynomial = 0xEDB88320; + static readonly uint crcSeed = 0xFFFFFFFF; + + static Crc32() + { + crcTable = new uint[256]; + + for (var i = 0; i < 256; i++) + { + var entry = (uint)i; + for (int j = 0; j < 8; j++) + { + if ((entry & 0x00000001) == 0x00000001) entry = (entry >> 1) ^ crcPolynomial; + else entry >>= 1; + } + crcTable[i] = entry; + } + } + + private static void VerifyStartAndLength(int dataLength, int segmentStart, int segmentLength) + { + if (segmentStart >= dataLength) throw new Exception("Segment start offset is greater than total length"); + if (segmentLength > dataLength) throw new Exception("Segment length is greater than total length"); + if ((segmentStart + segmentLength) > dataLength) throw new Exception("Segment end offset is greater than total length"); + } + + public static uint Calculate(FileInfo fileInfo) + { + return Calculate(fileInfo, 0, (int)fileInfo.Length); + } + + public static uint Calculate(FileInfo fileInfo, int start, int length) + { + VerifyStartAndLength((int)fileInfo.Length, start, length); + + using FileStream file = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + return Calculate(file, start, length); + } + + public static uint Calculate(Stream stream) + { + return Calculate(stream, 0, (int)stream.Length); + } + + public static uint Calculate(Stream stream, int start, int length) + { + VerifyStartAndLength((int)stream.Length, start, length); + + var lastStreamPosition = stream.Position; + var data = new byte[length]; + stream.Position = start; + stream.Read(data, 0, length); + var crc = Calculate(data, 0, data.Length); + stream.Position = lastStreamPosition; + + return crc; + } + + public static uint Calculate(byte[] data) + { + return Calculate(data, 0, data.Length); + } + + public static uint Calculate(byte[] data, int start, int length) + { + VerifyStartAndLength(data.Length, start, length); + + uint crc = crcSeed; + for (var i = start; i < (start + length); i++) + crc = ((crc >> 8) ^ crcTable[data[i] ^ (crc & 0x000000FF)]); + return ~crc; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs.meta new file mode 100644 index 0000000..3ace5b4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Crc32.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: afa4b03878ac3704bb52cae6e463f1f0 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs new file mode 100644 index 0000000..7e42f42 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.IO; + +using Serilog; +using Serilog.Core; +using Serilog.Events; +using Serilog.Formatting; +using Serilog.Formatting.Display; + +using StoicGoose.Common.Extensions; + +namespace StoicGoose.Common.Utilities +{ + public enum LogSeverity { Verbose, Debug, Information, Warning, Error, Fatal } + + public static class Log + { + const string defaultTemplate = "{Message}{NewLine}{Exception}"; + + readonly static Dictionary severityToEventLevelMapping = new() + { + { LogSeverity.Verbose, LogEventLevel.Verbose }, + { LogSeverity.Debug, LogEventLevel.Debug }, + { LogSeverity.Information, LogEventLevel.Information }, + { LogSeverity.Warning, LogEventLevel.Warning }, + { LogSeverity.Error, LogEventLevel.Error }, + { LogSeverity.Fatal, LogEventLevel.Fatal } + }; + + readonly static Dictionary logSeverityAnsiColors = new() + { + { LogSeverity.Verbose, Ansi.White }, + { LogSeverity.Debug, Ansi.Cyan }, + { LogSeverity.Information, Ansi.Green }, + { LogSeverity.Warning, Ansi.Yellow }, + { LogSeverity.Error, Ansi.Magenta }, + { LogSeverity.Fatal, Ansi.Red } + }; + + static Logger mainLogger = default; + static Logger fileLogger = default; + + public static string LogPath { get; private set; } = string.Empty; + + public static void Initialize(string logPath) + { + if (File.Exists(logPath)) File.Delete(logPath); + + mainLogger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Console(outputTemplate: defaultTemplate) + .CreateLogger(); + + fileLogger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.File(LogPath = logPath, restrictedToMinimumLevel: LogEventLevel.Verbose) + .CreateLogger(); + } + + public static void AttachTextWriter(TextWriter writer) + { + mainLogger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Sink(mainLogger) + .WriteTo.Sink(new TextWriterSink(writer, new MessageTemplateTextFormatter(defaultTemplate))) + .CreateLogger(); + } + + public static void WriteLine(string message) => Write(LogEventLevel.Information, message); + public static void WriteFatal(string message) => Write(LogEventLevel.Fatal, message); + + private static void Write(LogEventLevel logEventLevel, string message) + { + mainLogger?.Write(logEventLevel, message); + fileLogger?.Write(logEventLevel, message.RemoveAnsi()); + } + + public static void WriteEvent(LogSeverity severity, object source, string message) + { + if (mainLogger == null && fileLogger == null) return; + + var eventLevel = severityToEventLevelMapping.ContainsKey(severity) ? severityToEventLevelMapping[severity] : LogEventLevel.Verbose; + var logMessage = $"{logSeverityAnsiColors[severity]}[{source?.GetType().Name ?? string.Empty}]{Ansi.Reset}: {message}"; + mainLogger?.Write(eventLevel, logMessage); + fileLogger?.Write(eventLevel, logMessage.RemoveAnsi()); + } + } + + class TextWriterSink : ILogEventSink + { + readonly TextWriter textWriter = default; + readonly ITextFormatter textFormatter = default; + + readonly object syncRoot = new(); + + public TextWriterSink(TextWriter writer, ITextFormatter formatter) + { + textWriter = writer; + textFormatter = formatter ?? throw new ArgumentNullException(nameof(formatter)); + } + + public void Emit(LogEvent logEvent) + { + lock (syncRoot) + { + textFormatter.Format(logEvent ?? throw new ArgumentNullException(nameof(logEvent)), textWriter); + textWriter.Flush(); + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs.meta new file mode 100644 index 0000000..fae0e83 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Log.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 916e8e9742f5dfc41823c7eb3a544606 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs new file mode 100644 index 0000000..cf8747b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs @@ -0,0 +1,41 @@ +using System.IO; +using System.Reflection; + +using StoicGoose.Common.Drawing; + +namespace StoicGoose.Common.Utilities +{ + public static class Resources + { + private static Stream GetEmbeddedResourceStream(string name) + { + var assembly = Assembly.GetEntryAssembly(); + name = $"{assembly.GetName().Name}.{name}"; + return assembly.GetManifestResourceStream(name); + } + + public static RgbaFile GetEmbeddedRgbaFile(string name) + { + using var stream = GetEmbeddedResourceStream(name); + if (stream == null) return null; + return new RgbaFile(stream); + } + + public static string GetEmbeddedText(string name) + { + using var stream = GetEmbeddedResourceStream(name); + if (stream == null) return string.Empty; + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + public static byte[] GetEmbeddedRawData(string name) + { + using var stream = GetEmbeddedResourceStream(name); + if (stream == null) return null; + var buffer = new byte[stream.Length]; + stream.Read(buffer, 0, buffer.Length); + return buffer; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs.meta new file mode 100644 index 0000000..bd9abd7 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Common/Utilities/Resources.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 20f7f2e2f16528949b80073b5e8778f9 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core.meta new file mode 100644 index 0000000..87a21f1 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4feaaee1d7195a46a3aa956e4128489 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs new file mode 100644 index 0000000..6c8291d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs @@ -0,0 +1,41 @@ +using System; + +using StoicGoose.Core.Interfaces; + +namespace StoicGoose.Core +{ + public class Bootstrap : IComponent + { + readonly byte[] rom = Array.Empty(); + readonly uint romMask = 0; + + public Bootstrap(int size) + { + rom = new byte[size]; + romMask = (uint)(rom.Length - 1); + } + + public void Reset() + { + // + } + + public void Shutdown() + { + // + } + + public void LoadRom(byte[] data) + { + if (data.Length != rom.Length) + throw new Exception("Data size mismatch error"); + + Buffer.BlockCopy(data, 0, rom, 0, data.Length); + } + + public byte ReadMemory(uint address) + { + return rom[address & romMask]; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs.meta new file mode 100644 index 0000000..81f3bd4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Bootstrap.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d194949ecf04a5341b082bac647c847d \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU.meta new file mode 100644 index 0000000..89957c0 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1c58bce2e7f29f419b70dc124e97204 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs new file mode 100644 index 0000000..7d24034 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs @@ -0,0 +1,96 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + private byte ReadOpcodeEb() + { + ReadModRM(); + if (modRm.Mod == ModRM.Modes.Register) + return GetRegister8((RegisterNumber8)modRm.Mem); + else + return ReadMemory8(modRm.Segment, modRm.Offset); + } + + private ushort ReadOpcodeEw() + { + ReadModRM(); + if (modRm.Mod == ModRM.Modes.Register) + return GetRegister16((RegisterNumber16)modRm.Mem); + else + return ReadMemory16(modRm.Segment, modRm.Offset); + } + + private void WriteOpcodeEb(byte value) + { + ReadModRM(); + if (modRm.Mod == ModRM.Modes.Register) + SetRegister8((RegisterNumber8)modRm.Mem, value); + else + WriteMemory8(modRm.Segment, modRm.Offset, value); + } + + private void WriteOpcodeEw(ushort value) + { + ReadModRM(); + if (modRm.Mod == ModRM.Modes.Register) + SetRegister16((RegisterNumber16)modRm.Mem, value); + else + WriteMemory16(modRm.Segment, modRm.Offset, value); + } + + private byte ReadOpcodeGb() + { + ReadModRM(); + return GetRegister8((RegisterNumber8)modRm.Reg); + } + + private ushort ReadOpcodeGw() + { + ReadModRM(); + return GetRegister16((RegisterNumber16)modRm.Reg); + } + + private void WriteOpcodeGb(byte value) + { + ReadModRM(); + SetRegister8((RegisterNumber8)modRm.Reg, value); + } + + private void WriteOpcodeGw(ushort value) + { + ReadModRM(); + SetRegister16((RegisterNumber16)modRm.Reg, value); + } + + private ushort ReadOpcodeSw() + { + ReadModRM(); + return GetSegment((SegmentNumber)modRm.Reg); + } + + private void WriteOpcodeSw(ushort value) + { + ReadModRM(); + SetSegment((SegmentNumber)modRm.Reg, value); + } + + private byte ReadOpcodeIb() + { + return ReadMemory8(cs, ip++); + } + + private ushort ReadOpcodeIw() + { + var value = ReadMemory16(cs, ip); + ip += 2; + return value; + } + + private ushort ReadOpcodeJb() + { + var tmp1 = (ushort)(ip + 1); + var tmp2 = (sbyte)ReadOpcodeIb(); + return (ushort)(tmp1 + tmp2); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs.meta new file mode 100644 index 0000000..896b0df --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Addressing.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e1f6daccd87f15e48a0e766b94f6d27f \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs new file mode 100644 index 0000000..6176b02 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs @@ -0,0 +1,49 @@ +using System; + +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + [Flags] + public enum Flags : ushort + { + Carry = 1 << 0, /* CF */ + ReservedB1 = 1 << 1, /* (reserved) */ + Parity = 1 << 2, /* PF */ + ReservedB3 = 1 << 3, /* (reserved) */ + Auxiliary = 1 << 4, /* AF */ + ReservedB5 = 1 << 5, /* (reserved) */ + Zero = 1 << 6, /* ZF */ + Sign = 1 << 7, /* SF */ + Trap = 1 << 8, /* TF */ + InterruptEnable = 1 << 9, /* IF */ + Direction = 1 << 10, /* DF */ + Overflow = 1 << 11, /* OF */ + ReservedB12 = 1 << 12, /* (reserved) */ + ReservedB13 = 1 << 13, /* (reserved) */ + ReservedB14 = 1 << 14, /* (reserved) */ + ReservedB15 = 1 << 15 /* (reserved) */ + } + + private void SetFlags(Flags flags) + { + this.flags |= flags; + } + + private void ClearFlags(Flags flags) + { + this.flags &= ~flags; + } + + public bool IsFlagSet(Flags flags) + { + return (this.flags & flags) == flags; + } + + private void SetClearFlagConditional(Flags flags, bool condition) + { + if (condition) this.flags |= flags; + else this.flags &= ~flags; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs.meta new file mode 100644 index 0000000..df94a71 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Flags.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8d3774b3b6efb724ca93707535be9a35 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs new file mode 100644 index 0000000..bf54af7 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs @@ -0,0 +1,527 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + private byte Add8(bool withCarry, byte a, byte b) + { + int result = a + b + (withCarry && IsFlagSet(Flags.Carry) ? 1 : 0); + + // CF, PF, AF, ZF, SF, OF = according to result + SetClearFlagConditional(Flags.Carry, (result & 0x100) != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ b) & 0x80) != 0); + + return (byte)result; + } + + private ushort Add16(bool withCarry, ushort a, ushort b) + { + int result = a + b + (withCarry && IsFlagSet(Flags.Carry) ? 1 : 0); + + // CF, PF, AF, ZF, SF, OF = according to result + SetClearFlagConditional(Flags.Carry, (result & 0x10000) != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ b) & 0x8000) != 0); + + return (ushort)result; + } + + private byte Or8(byte a, byte b) + { + int result = a | b; + + // CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined + ClearFlags(Flags.Carry); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + ClearFlags(Flags.Overflow); + + return (byte)result; + } + + private ushort Or16(ushort a, ushort b) + { + int result = a | b; + + // CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined + ClearFlags(Flags.Carry); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + ClearFlags(Flags.Overflow); + + return (ushort)result; + } + + private byte Sub8(bool withBorrow, byte a, byte b) + { + int result = a - (b + (withBorrow && IsFlagSet(Flags.Carry) ? 1 : 0)); + + // CF, PF, AF, ZF, SF, OF = according to result + SetClearFlagConditional(Flags.Carry, (result & 0x100) != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ b) & 0x80) != 0); + + return (byte)result; + } + + private ushort Sub16(bool withBorrow, ushort a, ushort b) + { + int result = a - (b + (withBorrow && IsFlagSet(Flags.Carry) ? 1 : 0)); + + // CF, PF, AF, ZF, SF, OF = according to result + SetClearFlagConditional(Flags.Carry, (result & 0x10000) != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ b ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ b) & 0x8000) != 0); + + return (ushort)result; + } + + private byte And8(byte a, byte b) + { + int result = a & b; + + // CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined + ClearFlags(Flags.Carry); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + ClearFlags(Flags.Overflow); + + return (byte)result; + } + + private ushort And16(ushort a, ushort b) + { + int result = a & b; + + // CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined + ClearFlags(Flags.Carry); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + ClearFlags(Flags.Overflow); + + return (ushort)result; + } + + private void Daa(bool isSubtract) + { + byte oldAl = ax.Low; + + if (((oldAl & 0x0F) > 0x09) || IsFlagSet(Flags.Auxiliary)) + { + ax.Low += (byte)(isSubtract ? -0x06 : 0x06); + SetFlags(Flags.Auxiliary); + } + else + ClearFlags(Flags.Auxiliary); + + if ((oldAl > 0x99) || IsFlagSet(Flags.Carry)) + { + ax.Low += (byte)(isSubtract ? -0x60 : 0x60); + SetFlags(Flags.Carry); + } + else + ClearFlags(Flags.Carry); + + SetClearFlagConditional(Flags.Parity, CalculateParity(ax.Low & 0xFF)); + SetClearFlagConditional(Flags.Zero, (ax.Low & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (ax.Low & 0x80) != 0); + } + + private byte Xor8(byte a, byte b) + { + int result = a ^ b; + + // CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined + ClearFlags(Flags.Carry); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + ClearFlags(Flags.Overflow); + + return (byte)result; + } + + private ushort Xor16(ushort a, ushort b) + { + int result = a ^ b; + + // CF, OF = cleared; PF, ZF, SF = according to result; AF = undefined + ClearFlags(Flags.Carry); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + ClearFlags(Flags.Overflow); + + return (ushort)result; + } + + private void Aaa(bool isSubtract) + { + if (((ax.Low & 0x0F) > 0x09) || IsFlagSet(Flags.Auxiliary)) + { + ax.Low = (byte)(ax.Low + (isSubtract ? -0x06 : 0x06)); + ax.High = (byte)(ax.High + (isSubtract ? -0x01 : 0x01)); + + SetFlags(Flags.Auxiliary); + SetFlags(Flags.Carry); + } + else + { + ClearFlags(Flags.Auxiliary); + ClearFlags(Flags.Carry); + } + + ax.Low &= 0x0F; + } + + private byte Inc8(byte a) + { + int result = a + 1; + + // PF, AF, ZF, SF, OF = according to result, CF = undefined + //Carry + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ 1) & 0x80) != 0); + + return (byte)result; + } + + private ushort Inc16(ushort a) + { + int result = a + 1; + + // PF, AF, ZF, SF, OF = according to result, CF = undefined + //Carry + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (result ^ 1) & 0x8000) != 0); + + return (ushort)result; + } + + private byte Dec8(byte a) + { + int result = a - 1; + + // PF, AF, ZF, SF, OF = according to result, CF = undefined + //Carry + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ 1) & 0x80) != 0); + + return (byte)result; + } + + private ushort Dec16(ushort a) + { + int result = a - 1; + + // PF, AF, ZF, SF, OF = according to result, CF = undefined + //Carry + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((a ^ 1 ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ a) & (a ^ 1) & 0x8000) != 0); + + return (ushort)result; + } + + private byte Rol8(bool withCarry, byte a, byte b) + { + int result; + + if (withCarry) + { + result = a; + for (var n = 0; n < b; n++) + { + var carry = result & 0x80; + result = (result << 1) | (IsFlagSet(Flags.Carry) ? 0x01 : 0); + SetClearFlagConditional(Flags.Carry, carry != 0); + } + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0); + result &= 0xFF; + } + else + { + result = (a << b) | (a >> (8 - b)); + SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 8)) != 0); + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0); + result &= 0xFF; + } + + return (byte)result; + } + + private ushort Rol16(bool withCarry, ushort a, ushort b) + { + int result; + + if (withCarry) + { + result = a; + for (var n = 0; n < b; n++) + { + var carry = result & 0x80; + result = (result << 1) | (IsFlagSet(Flags.Carry) ? 0x0001 : 0); + SetClearFlagConditional(Flags.Carry, carry != 0); + } + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0); + result &= 0xFFFF; + } + else + { + result = (a << b) | (a >> (16 - b)); + SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 16)) != 0); + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0); + result &= 0xFFFF; + } + + return (ushort)result; + } + + private byte Ror8(bool withCarry, byte a, byte b) + { + int result; + + if (withCarry) + { + result = a; + for (var n = 0; n < b; n++) + { + var carry = result & 0x01; + result = (IsFlagSet(Flags.Carry) ? 0x80 : 0) | (result >> 1); + SetClearFlagConditional(Flags.Carry, carry != 0); + } + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0); + result &= 0xFF; + } + else + { + result = (a >> b) | (a << (8 - b)); + SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & 0x01) != 0); + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0); + result &= 0xFF; + } + + return (byte)result; + } + + private ushort Ror16(bool withCarry, ushort a, ushort b) + { + int result; + + if (withCarry) + { + result = a; + for (var n = 0; n < b; n++) + { + var carry = result & 0x01; + result = (IsFlagSet(Flags.Carry) ? 0x8000 : 0) | (result >> 1); + SetClearFlagConditional(Flags.Carry, carry != 0); + } + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0); + result &= 0xFFFF; + } + else + { + result = (a >> b) | (a << (16 - b)); + SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & 0x01) != 0); + SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0); + result &= 0xFFFF; + } + + return (ushort)result; + } + + private byte Shl8(byte a, byte b) + { + int result = (a << b) & 0xFF; + + if (b != 0) + { + SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 8)) != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + if (b == 1) SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x80) != 0); + } + + return (byte)result; + } + + private ushort Shl16(ushort a, ushort b) + { + int result = (a << b) & 0xFFFF; + + if (b != 0) + { + SetClearFlagConditional(Flags.Carry, ((a << b) & (1 << 16)) != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + if (b == 1) SetClearFlagConditional(Flags.Overflow, ((a ^ result) & 0x8000) != 0); + } + + return (ushort)result; + } + + private byte Shr8(bool signed, byte a, byte b) + { + if (signed && (b & 16) != 0) + { + SetClearFlagConditional(Flags.Carry, (a & 0x80) != 0); + return (byte)(0 - (IsFlagSet(Flags.Carry) ? 1 : 0)); + } + + int result = (a >> b) & 0xFF; + + SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & (1 << 0)) != 0); + if (signed && (a & 0x80) != 0) result |= 0xFF << (8 - b); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + SetClearFlagConditional(Flags.Overflow, !signed && ((a ^ result) & 0x80) != 0); + + return (byte)result; + } + + private ushort Shr16(bool signed, ushort a, ushort b) + { + if (signed && (b & 16) != 0) + { + SetClearFlagConditional(Flags.Carry, (a & 0x8000) != 0); + return (ushort)(0 - (IsFlagSet(Flags.Carry) ? 1 : 0)); + } + + int result = (a >> b) & 0xFFFF; + + SetClearFlagConditional(Flags.Carry, ((a >> (b - 1)) & (1 << 0)) != 0); + if (signed && (a & 0x8000) != 0) result |= 0xFFFF << (16 - b); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + //Aux + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + SetClearFlagConditional(Flags.Overflow, !signed && ((a ^ result) & 0x8000) != 0); + + return (ushort)result; + } + + private byte Neg8(byte b) + { + int result = -b & 0xFF; + + // CF = is operand non-zero?; PF, AF, ZF, SF, OF = according to result + SetClearFlagConditional(Flags.Carry, b != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((0 ^ b ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x80) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ 0) & (0 ^ b) & 0x80) != 0); + + return (byte)result; + } + + private ushort Neg16(ushort b) + { + int result = -b & 0xFFFF; + + // CF = is operand non-zero?; PF, AF, ZF, SF, OF = according to result + SetClearFlagConditional(Flags.Carry, b != 0); + SetClearFlagConditional(Flags.Parity, CalculateParity(result & 0xFF)); + SetClearFlagConditional(Flags.Auxiliary, ((0 ^ b ^ result) & 0x10) != 0); + SetClearFlagConditional(Flags.Zero, (result & 0xFFFF) == 0); + SetClearFlagConditional(Flags.Sign, (result & 0x8000) != 0); + SetClearFlagConditional(Flags.Overflow, ((result ^ 0) & (0 ^ b) & 0x8000) != 0); + + return (ushort)result; + } + + private ushort Mul8(bool signed, byte a, byte b) + { + uint result = (uint)(signed ? ((sbyte)a * (sbyte)b) : (a * b)); + + // CF, OF = is upper half of result non-zero?; PF, AF, ZF, SF = undefined + SetClearFlagConditional(Flags.Overflow, (result >> 8) != 0); + SetClearFlagConditional(Flags.Carry, (result >> 8) != 0); + + return (ushort)result; + } + + private uint Mul16(bool signed, ushort a, ushort b) + { + uint result = (uint)(signed ? ((short)a * (short)b) : (a * b)); + + // CF, OF = is upper half of result non-zero?; PF, AF, ZF, SF = undefined + SetClearFlagConditional(Flags.Overflow, (result >> 16) != 0); + SetClearFlagConditional(Flags.Carry, (result >> 16) != 0); + + return (uint)result; + } + + private ushort Div8(bool signed, ushort a, byte b) + { + if (b == 0) + { + Interrupt(0); + return a; + } + + int quotient = signed ? ((short)a / (sbyte)b) : (a / b); + int remainder = signed ? ((short)a % (sbyte)b) : (a % b); + + // CF, PF, AF, ZF, SF, OF = undefined + + return (ushort)(((remainder & 0xFF) << 8) | (quotient & 0xFF)); + } + + private uint Div16(bool signed, uint a, ushort b) + { + if (b == 0) + { + Interrupt(0); + return a; + } + + int quotient = signed ? ((int)a / (short)b) : (int)(a / b); + int remainder = signed ? ((int)a % (short)b) : (int)(a % b); + + // CF, PF, AF, ZF, SF, OF = undefined + + return (uint)(((remainder & 0xFFFF) << 16) | (quotient & 0xFFFF)); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs.meta new file mode 100644 index 0000000..6d72ba9 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Implementations.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5828627e3b453af4f9d1280493414226 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs new file mode 100644 index 0000000..bec472f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs @@ -0,0 +1,37 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + private byte ReadMemory8(ushort segment, ushort offset) + { + return machine.ReadMemory((uint)((segment << 4) + offset)); + } + + private ushort ReadMemory16(ushort segment, ushort offset) + { + return (ushort)((machine.ReadMemory((uint)((segment << 4) + offset + 1)) << 8) | machine.ReadMemory((uint)((segment << 4) + offset))); + } + + private void WriteMemory8(ushort segment, ushort offset, byte value) + { + machine.WriteMemory((uint)((segment << 4) + offset), value); + } + + private void WriteMemory16(ushort segment, ushort offset, ushort value) + { + machine.WriteMemory((uint)((segment << 4) + offset), (byte)(value & 0xFF)); + machine.WriteMemory((uint)((segment << 4) + offset + 1), (byte)(value >> 8)); + } + + private ushort ReadPort16(ushort port) + { + return (ushort)(machine.ReadPort((ushort)(port + 1)) << 8 | machine.ReadPort(port)); + } + + private void WritePort16(ushort port, ushort value) + { + machine.WritePort(port, (byte)(value & 0xFF)); + machine.WritePort((ushort)(port + 1), (byte)(value >> 8)); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs.meta new file mode 100644 index 0000000..dd169ae --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Memory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9fbe65ebef4c3df439fcb960d59e10f6 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs new file mode 100644 index 0000000..85fd8c2 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs @@ -0,0 +1,48 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + private void Push(ushort value) + { + sp -= 2; + WriteMemory16(ss, sp, value); + } + + private ushort Pop() + { + var value = ReadMemory16(ss, sp); + sp += 2; + return value; + } + + private int Loop() + { + if (--cx.Word != 0) { ip = ReadOpcodeJb(); return 4; } + else { ip++; return 1; } + } + + private int LoopWhile(bool condition) + { + if (--cx.Word != 0 && condition) { ip = ReadOpcodeJb(); return 5; } + else { ip++; return 2; } + } + + private int JumpConditional(bool condition) + { + if (condition) { ip = ReadOpcodeJb(); return 4; } + else { ip++; return 1; } + } + + private static bool CalculateParity(int result) + { + int bitsSet = 0; + while (result != 0) { bitsSet += result & 0x01; result >>= 1; } + return bitsSet == 0 || (bitsSet % 2) == 0; + } + + private static void Exchange(ref ushort a, ref ushort b) + { + (b, a) = (a, b); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs.meta new file mode 100644 index 0000000..3879699 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Miscellaneous.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 253866b049a8cb445ab91a6c6cbb65e7 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs new file mode 100644 index 0000000..6e56bae --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs @@ -0,0 +1,103 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + ModRM modRm; + + private void ReadModRM() + { + if (modRm.IsSet) return; + + modRm.Set(ReadMemory8(cs, ip++)); + switch (modRm.Mod) + { + case ModRM.Modes.NoDisplacement: + switch (modRm.Mem) + { + case 0b000: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + si); break; + case 0b001: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + di); break; + case 0b010: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + si); break; + case 0b011: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + di); break; + case 0b100: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = si; break; + case 0b101: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = di; break; + case 0b110: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = ReadMemory16(cs, ip); ip += 2; break; + case 0b111: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = bx.Word; break; + } + break; + + case ModRM.Modes.OneByteDisplacement: + { + var displacement = (sbyte)ReadMemory8(cs, ip); + ip++; + switch (modRm.Mem) + { + case 0b000: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + si + displacement); break; + case 0b001: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + di + displacement); break; + case 0b010: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + si + displacement); break; + case 0b011: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + di + displacement); break; + case 0b100: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(si + displacement); break; + case 0b101: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(di + displacement); break; + case 0b110: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + displacement); break; + case 0b111: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + displacement); break; + } + } + break; + + case ModRM.Modes.TwoByteDisplacement: + { + var displacement = (short)ReadMemory16(cs, ip); + ip += 2; + switch (modRm.Mem) + { + case 0b000: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + si + displacement); break; + case 0b001: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + di + displacement); break; + case 0b010: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + si + displacement); break; + case 0b011: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + di + displacement); break; + case 0b100: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(si + displacement); break; + case 0b101: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(di + displacement); break; + case 0b110: modRm.Segment = GetSegmentViaOverride(SegmentNumber.SS); modRm.Offset = (ushort)(bp + displacement); break; + case 0b111: modRm.Segment = GetSegmentViaOverride(SegmentNumber.DS); modRm.Offset = (ushort)(bx.Word + displacement); break; + } + } + break; + } + } + + struct ModRM + { + public enum Modes : byte + { + NoDisplacement = 0b00, + OneByteDisplacement = 0b01, + TwoByteDisplacement = 0b10, + Register = 0b11 + } + + byte data; + + public Modes Mod => (Modes)((data >> 6) & 0b11); + public byte Reg => (byte)((data >> 3) & 0b111); + public byte Mem => (byte)((data >> 0) & 0b111); + + public ushort Segment, Offset; + + public bool IsSet; + + public void Set(byte value) + { + data = value; + + IsSet = true; + } + + public void Reset() + { + data = 0; + Segment = 0; + Offset = 0; + + IsSet = false; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs.meta new file mode 100644 index 0000000..f6572ae --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.ModRM.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a81e97a11c345494da1d600ffa5e81c2 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs new file mode 100644 index 0000000..ec4a90a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs @@ -0,0 +1,905 @@ +using System; + +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + delegate int Instruction(V30MZ cpu); + readonly static Instruction[] instructions = new Instruction[256] + { + /* 0x00 */ /* ADD Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.Add8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* ADD Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.Add16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* ADD Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.Add8(false, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* ADD Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.Add16(false, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x04 */ /* ADD AL Ib */ (cpu) => { cpu.ax.Low = cpu.Add8(false, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* ADD AX Iw */ (cpu) => { cpu.ax.Word = cpu.Add16(false, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* PUSH ES */ (cpu) => { cpu.Push(cpu.es); return 1; }, + /* POP ES */ (cpu) => { cpu.es = cpu.Pop(); return 1; }, + /* 0x08 */ /* OR Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.Or8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* OR Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.Or16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* OR Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.Or8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* OR Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.Or16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x0C */ /* OR AL Ib */ (cpu) => { cpu.ax.Low = cpu.Or8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* OR AX Iw */ (cpu) => { cpu.ax.Word = cpu.Or16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* PUSH CS */ (cpu) => { cpu.Push(cpu.cs); return 1; }, + /* (Invalid; NOP?) */ (cpu) => 3, + + /* 0x10 */ /* ADC Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.Add8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* ADC Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.Add16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* ADC Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.Add8(true, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* ADC Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.Add16(true, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x14 */ /* ADC AL Ib */ (cpu) => { cpu.ax.Low = cpu.Add8(true, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* ADC AX Iw */ (cpu) => { cpu.ax.Word = cpu.Add16(true, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* PUSH SS */ (cpu) => { cpu.Push(cpu.ss); return 1; }, + /* POP SS */ (cpu) => { cpu.ss = cpu.Pop(); return 1; }, + /* 0x18 */ /* SBB Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.Sub8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* SBB Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.Sub16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* SBB Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.Sub8(true, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* SBB Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.Sub16(true, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x1C */ /* SBB AL Ib */ (cpu) => { cpu.ax.Low = cpu.Sub8(true, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* SBB AX Iw */ (cpu) => { cpu.ax.Word = cpu.Sub16(true, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* PUSH DS */ (cpu) => { cpu.Push(cpu.ds); return 1; }, + /* POP DS */ (cpu) => { cpu.ds = cpu.Pop(); return 1; }, + + /* 0x20 */ /* AND Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.And8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* AND Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.And16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* AND Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.And8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* AND Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.And16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x24 */ /* AND AL Ib */ (cpu) => { cpu.ax.Low = cpu.And8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* AND AX Iw */ (cpu) => { cpu.ax.Word = cpu.And16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* (Prefix ES) */ (cpu) => 0, + /* DAA */ (cpu) => { cpu.Daa(false); return 10; }, + /* 0x28 */ /* SUB Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* SUB Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* SUB Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.Sub8(false, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* SUB Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.Sub16(false, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x2C */ /* SUB AL Ib */ (cpu) => { cpu.ax.Low = cpu.Sub8(false, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* SUB AX Iw */ (cpu) => { cpu.ax.Word = cpu.Sub16(false, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* (Prefix CS) */ (cpu) => 0, + /* DAS */ (cpu) => { cpu.Daa(true); return 10; }, + + /* 0x30 */ /* XOR Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.Xor8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb())); return 1; }, + /* XOR Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.Xor16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw())); return 1; }, + /* XOR Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.Xor8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb())); return 1; }, + /* XOR Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.Xor16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw())); return 1; }, + /* 0x34 */ /* XOR AL Ib */ (cpu) => { cpu.ax.Low = cpu.Xor8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* XOR AX Iw */ (cpu) => { cpu.ax.Word = cpu.Xor16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* (Prefix SS) */ (cpu) => 0, + /* AAA */ (cpu) => { cpu.Aaa(false); return 9; }, + /* 0x38 */ /* CMP Eb Gb */ (cpu) => { cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeGb()); return 1; }, + /* CMP Ew Gw */ (cpu) => { cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeGw()); return 1; }, + /* CMP Gb Eb */ (cpu) => { cpu.Sub8(false, cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb()); return 1; }, + /* CMP Gw Ew */ (cpu) => { cpu.Sub16(false, cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw()); return 1; }, + /* 0x3C */ /* CMP AL Ib */ (cpu) => { cpu.Sub8(false, cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* CMP AX Iw */ (cpu) => { cpu.Sub16(false, cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* (Prefix DS) */ (cpu) => 0, + /* AAS */ (cpu) => { cpu.Aaa(true); return 9; }, + + /* 0x40 */ /* INC AX */ (cpu) => { cpu.ax.Word = cpu.Inc16(cpu.ax.Word); return 1; }, + /* INC CX */ (cpu) => { cpu.cx.Word = cpu.Inc16(cpu.cx.Word); return 1; }, + /* INC DX */ (cpu) => { cpu.dx.Word = cpu.Inc16(cpu.dx.Word); return 1; }, + /* INC BX */ (cpu) => { cpu.bx.Word = cpu.Inc16(cpu.bx.Word); return 1; }, + /* 0x44 */ /* INC SP */ (cpu) => { cpu.sp = cpu.Inc16(cpu.sp); return 1; }, + /* INC BP */ (cpu) => { cpu.bp = cpu.Inc16(cpu.bp); return 1; }, + /* INC SI */ (cpu) => { cpu.si = cpu.Inc16(cpu.si); return 1; }, + /* INC DI */ (cpu) => { cpu.di = cpu.Inc16(cpu.di); return 1; }, + /* 0x48 */ /* DEC AX */ (cpu) => { cpu.ax.Word = cpu.Dec16(cpu.ax.Word); return 1; }, + /* DEC CX */ (cpu) => { cpu.cx.Word = cpu.Dec16(cpu.cx.Word); return 1; }, + /* DEC DX */ (cpu) => { cpu.dx.Word = cpu.Dec16(cpu.dx.Word); return 1; }, + /* DEC BX */ (cpu) => { cpu.bx.Word = cpu.Dec16(cpu.bx.Word); return 1; }, + /* 0x4C */ /* DEC SP */ (cpu) => { cpu.sp = cpu.Dec16(cpu.sp); return 1; }, + /* DEC BP */ (cpu) => { cpu.bp = cpu.Dec16(cpu.bp); return 1; }, + /* DEC SI */ (cpu) => { cpu.si = cpu.Dec16(cpu.si); return 1; }, + /* DEC DI */ (cpu) => { cpu.di = cpu.Dec16(cpu.di); return 1; }, + + /* 0x50 */ /* PUSH AX */ (cpu) => { cpu.Push(cpu.ax.Word); return 1; }, + /* PUSH CX */ (cpu) => { cpu.Push(cpu.cx.Word); return 1; }, + /* PUSH DX */ (cpu) => { cpu.Push(cpu.dx.Word); return 1; }, + /* PUSH BX */ (cpu) => { cpu.Push(cpu.bx.Word); return 1; }, + /* 0x54 */ /* PUSH SP */ (cpu) => { cpu.Push(cpu.sp); return 1; }, + /* PUSH BP */ (cpu) => { cpu.Push(cpu.bp); return 1; }, + /* PUSH SI */ (cpu) => { cpu.Push(cpu.si); return 1; }, + /* PUSH DI */ (cpu) => { cpu.Push(cpu.di); return 1; }, + /* 0x58 */ /* POP AX */ (cpu) => { cpu.ax.Word = cpu.Pop(); return 1; }, + /* POP CX */ (cpu) => { cpu.cx.Word = cpu.Pop(); return 1; }, + /* POP DX */ (cpu) => { cpu.dx.Word = cpu.Pop(); return 1; }, + /* POP BX */ (cpu) => { cpu.bx.Word = cpu.Pop(); return 1; }, + /* 0x5C */ /* POP SP */ (cpu) => { cpu.sp = cpu.Pop(); return 1; }, + /* POP BP */ (cpu) => { cpu.bp = cpu.Pop(); return 1; }, + /* POP SI */ (cpu) => { cpu.si = cpu.Pop(); return 1; }, + /* POP DI */ (cpu) => { cpu.di = cpu.Pop(); return 1; }, + + /* 0x60 */ /* PUSHA */ Opcode0x60, + /* POPA */ Opcode0x61, + /* BOUND Gw E */ Opcode0x62, + /* (Invalid; NOP?) */ (cpu) => 3, + /* 0x64 */ /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* 0x68 */ /* PUSH Iw */ (cpu) => { cpu.Push(cpu.ReadOpcodeIw()); return 1; }, + /* IMUL Gw Ew Iw */ (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeGw((ushort)cpu.Mul16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); return 4; }, + /* PUSH Ib */ (cpu) => { cpu.Push((ushort)(sbyte)cpu.ReadOpcodeIb()); return 1; }, + /* IMUL Gb Eb Ib */ (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeGw((ushort)cpu.Mul16(true, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); return 4; }, + /* 0x6C */ /* INSB */ Opcode0x6C, + /* INSW */ Opcode0x6D, + /* OUTSB */ Opcode0x6E, + /* OUTSW */ Opcode0x6F, + + /* 0x70 */ /* JO */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Overflow)), + /* JNO */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Overflow)), + /* JB */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Carry)), + /* JNB */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Carry)), + /* 0x74 */ /* JZ */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Zero)), + /* JNZ */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Zero)), + /* JBE */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Carry) || cpu.IsFlagSet(Flags.Zero)), + /* JA */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Carry) && !cpu.IsFlagSet(Flags.Zero)), + /* 0x78 */ /* JS */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Sign)), + /* JNS */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Sign)), + /* JPE */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Parity)), + /* JPO */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Parity)), + /* 0x7C */ /* JL */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Zero) && cpu.IsFlagSet(Flags.Sign) != cpu.IsFlagSet(Flags.Overflow)), + /* JGE */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Zero) || cpu.IsFlagSet(Flags.Sign) == cpu.IsFlagSet(Flags.Overflow)), + /* JLE */ (cpu) => cpu.JumpConditional(cpu.IsFlagSet(Flags.Zero) || cpu.IsFlagSet(Flags.Sign) != cpu.IsFlagSet(Flags.Overflow)), + /* JG */ (cpu) => cpu.JumpConditional(!cpu.IsFlagSet(Flags.Zero) && cpu.IsFlagSet(Flags.Sign) == cpu.IsFlagSet(Flags.Overflow)), + + /* 0x80 */ /* GRP1 Eb Ib */ Opcode0x80, + /* GRP1 Ew Iw */ Opcode0x81, + /* GRP1 Eb Ib */ Opcode0x80, + /* GRP1 Ew Ib */ Opcode0x83, + /* 0x84 */ /* TEST Gb Eb */ (cpu) => { cpu.And8(cpu.ReadOpcodeGb(), cpu.ReadOpcodeEb()); return 1; }, + /* TEST Gw Ew */ (cpu) => { cpu.And16(cpu.ReadOpcodeGw(), cpu.ReadOpcodeEw()); return 1; }, + /* XCHG Gb Eb */ (cpu) => { var temp = cpu.ReadOpcodeGb(); cpu.WriteOpcodeGb(cpu.ReadOpcodeEb()); cpu.WriteOpcodeEb(temp); return 3; }, + /* XCHG Gw Ew */ (cpu) => { var temp = cpu.ReadOpcodeGw(); cpu.WriteOpcodeGw(cpu.ReadOpcodeEw()); cpu.WriteOpcodeEw(temp); return 3; }, + /* 0x88 */ /* MOV Eb Gb */ (cpu) => { cpu.WriteOpcodeEb(cpu.ReadOpcodeGb()); return 1; }, + /* MOV Ew Gw */ (cpu) => { cpu.WriteOpcodeEw(cpu.ReadOpcodeGw()); return 1; }, + /* MOV Gb Eb */ (cpu) => { cpu.WriteOpcodeGb(cpu.ReadOpcodeEb()); return 1; }, + /* MOV Gw Ew */ (cpu) => { cpu.WriteOpcodeGw(cpu.ReadOpcodeEw()); return 1; }, + /* 0x8C */ /* MOV Ew Sw */ (cpu) => { cpu.WriteOpcodeEw(cpu.ReadOpcodeSw()); return 1; }, + /* LEA Gw M */ Opcode0x8D, + /* MOV Sw Ew */ (cpu) => { cpu.WriteOpcodeSw(cpu.ReadOpcodeEw()); return 1; }, + /* POP Ew */ (cpu) => { cpu.WriteOpcodeEw(cpu.Pop()); return 1; }, + + /* 0x90 */ /* NOP (XCHG AX AX) */ (cpu) => { Exchange(ref cpu.ax.Word, ref cpu.ax.Word); return 3; }, + /* XCHG CX AX */ (cpu) => { Exchange(ref cpu.cx.Word, ref cpu.ax.Word); return 3; }, + /* XCHG DX AX */ (cpu) => { Exchange(ref cpu.dx.Word, ref cpu.ax.Word); return 3; }, + /* XCHG BX AX */ (cpu) => { Exchange(ref cpu.bx.Word, ref cpu.ax.Word); return 3; }, + /* 0x94 */ /* XCHG SP AX */ (cpu) => { Exchange(ref cpu.sp, ref cpu.ax.Word); return 3; }, + /* XCHG BP AX */ (cpu) => { Exchange(ref cpu.bp, ref cpu.ax.Word); return 3; }, + /* XCHG SI AX */ (cpu) => { Exchange(ref cpu.si, ref cpu.ax.Word); return 3; }, + /* XCHG DI AX */ (cpu) => { Exchange(ref cpu.di, ref cpu.ax.Word); return 3; }, + /* 0x98 */ /* CBW */ (cpu) => { cpu.ax.Word = (ushort)(sbyte)cpu.ax.Low; return 2; }, + /* CWD */ (cpu) => { var value = (uint)(short)cpu.ax.Word; cpu.dx.Word = (ushort)((value >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((value >> 0) & 0xFFFF); return 2; }, + /* CALL Ap */ Opcode0x9A, + /* WAIT */ (cpu) => 1, + /* 0x9C */ /* PUSHF */ (cpu) => { cpu.Push((ushort)cpu.flags); return 1; }, + /* POPF */ (cpu) => { cpu.flags = (Flags)cpu.Pop(); return 1; }, + /* SAHF */ Opcode0x9E, + /* LAHF */ (cpu) => { cpu.ax.High = (byte)cpu.flags; return 2; }, + + /* 0xA0 */ /* MOV AL Aw */ (cpu) => { cpu.ax.Low = cpu.ReadMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw()); return 1; }, + /* MOV AX Aw */ (cpu) => { cpu.ax.Word = cpu.ReadMemory16(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw()); return 1; }, + /* MOV Aw AL */ (cpu) => { cpu.WriteMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw(), cpu.ax.Low); return 1; }, + /* MOV Aw AX */ (cpu) => { cpu.WriteMemory16(cpu.GetSegmentViaOverride(SegmentNumber.DS), cpu.ReadOpcodeIw(), cpu.ax.Word); return 1; }, + /* 0xA4 */ /* MOVSB */ Opcode0xA4, + /* MOVSW */ Opcode0xA5, + /* CMPSB */ Opcode0xA6, + /* CMPSW */ Opcode0xA7, + /* 0xA8 */ /* TEST AL Ib */ (cpu) => { cpu.And8(cpu.ax.Low, cpu.ReadOpcodeIb()); return 1; }, + /* TEST AX Iw */ (cpu) => { cpu.And16(cpu.ax.Word, cpu.ReadOpcodeIw()); return 1; }, + /* STOSB */ Opcode0xAA, + /* STOSW */ Opcode0xAB, + /* 0xAC */ /* LODSB */ Opcode0xAC, + /* LODSW */ Opcode0xAD, + /* SCASB */ Opcode0xAE, + /* SCASW */ Opcode0xAF, + + /* 0xB0 */ /* MOV AL Ib */ (cpu) => { cpu.ax.Low = cpu.ReadOpcodeIb(); return 1; }, + /* MOV CL Ib */ (cpu) => { cpu.cx.Low = cpu.ReadOpcodeIb(); return 1; }, + /* MOV DL Ib */ (cpu) => { cpu.dx.Low = cpu.ReadOpcodeIb(); return 1; }, + /* MOV BL Ib */ (cpu) => { cpu.bx.Low = cpu.ReadOpcodeIb(); return 1; }, + /* 0xB4 */ /* MOV AH Ib */ (cpu) => { cpu.ax.High = cpu.ReadOpcodeIb(); return 1; }, + /* MOV CH Ib */ (cpu) => { cpu.cx.High = cpu.ReadOpcodeIb(); return 1; }, + /* MOV DH Ib */ (cpu) => { cpu.dx.High = cpu.ReadOpcodeIb(); return 1; }, + /* MOV BH Ib */ (cpu) => { cpu.bx.High = cpu.ReadOpcodeIb(); return 1; }, + /* 0xB8 */ /* MOV AX Iw */ (cpu) => { cpu.ax.Word = cpu.ReadOpcodeIw(); return 1; }, + /* MOV CX Iw */ (cpu) => { cpu.cx.Word = cpu.ReadOpcodeIw(); return 1; }, + /* MOV DX Iw */ (cpu) => { cpu.dx.Word = cpu.ReadOpcodeIw(); return 1; }, + /* MOV BX Iw */ (cpu) => { cpu.bx.Word = cpu.ReadOpcodeIw(); return 1; }, + /* 0xBC */ /* MOV SP Iw */ (cpu) => { cpu.sp = cpu.ReadOpcodeIw(); return 1; }, + /* MOV BP Iw */ (cpu) => { cpu.bp = cpu.ReadOpcodeIw(); return 1; }, + /* MOV SI Iw */ (cpu) => { cpu.si = cpu.ReadOpcodeIw(); return 1; }, + /* MOV DI Iw */ (cpu) => { cpu.di = cpu.ReadOpcodeIw(); return 1; }, + + /* 0xC0 */ /* GRP2 Eb Ib */ Opcode0xC0, + /* GRP2 Ew Ib */ Opcode0xC1, + /* RET Iw */ (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.ip = cpu.Pop(); cpu.sp += offset; return 5; }, + /* RET */ (cpu) => { cpu.ip = cpu.Pop(); return 5; }, + /* 0xC4 */ /* LES Gw Mp */ Opcode0xC4, + /* LDS Gw Mp */ Opcode0xC5, + /* MOV Eb Ib */ (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeEb(cpu.ReadOpcodeIb()); return 1; }, + /* MOV Ew Iw */ (cpu) => { cpu.ReadModRM(); cpu.WriteOpcodeEw(cpu.ReadOpcodeIw()); return 1; }, + /* 0xC8 */ /* ENTER */ Opcode0xC8, + /* LEAVE */ (cpu) => { cpu.sp = cpu.bp; cpu.bp = cpu.Pop(); return 1; }, + /* RETF Iw */ (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.ip = cpu.Pop(); cpu.cs = cpu.Pop(); cpu.sp += offset; return 8; }, + /* RETF */ (cpu) => { cpu.ip = cpu.Pop(); cpu.cs = cpu.Pop(); return 7; }, + /* 0xCC */ /* INT 3 */ (cpu) => { cpu.Interrupt(3); return 8; }, + /* INT Ib */ (cpu) => { cpu.Interrupt(cpu.ReadOpcodeIb()); return 9; }, + /* INTO */ (cpu) => { if (cpu.IsFlagSet(Flags.Overflow)) cpu.Interrupt(4); return 5; }, + /* IRET */ (cpu) => { cpu.ip = cpu.Pop(); cpu.cs = cpu.Pop(); cpu.flags = (Flags)cpu.Pop(); return 9; }, + + /* 0xD0 */ /* GRP2 Eb 1 */ Opcode0xD0, + /* GRP2 Ew 1 */ Opcode0xD1, + /* GRP2 Eb CL */ Opcode0xD2, + /* GRP2 Ew CL */ Opcode0xD3, + /* 0xD4 */ /* AAM */ Opcode0xD4, + /* AAD */ Opcode0xD5, + /* (undocumented XLAT) */ (cpu) => { cpu.ax.Low = cpu.ReadMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), (ushort)(cpu.bx.Word + cpu.ax.Low)); return 4; }, + /* XLAT */ (cpu) => { cpu.ax.Low = cpu.ReadMemory8(cpu.GetSegmentViaOverride(SegmentNumber.DS), (ushort)(cpu.bx.Word + cpu.ax.Low)); return 4; }, + /* 0xD8 */ /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* 0xDC */ /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Invalid; NOP?) */ (cpu) => 3, + + /* 0xE0 */ /* LOOPNZ Jb */ (cpu) => { return cpu.LoopWhile(!cpu.IsFlagSet(Flags.Zero)); }, + /* LOOPZ Jb */ (cpu) => { return cpu.LoopWhile(cpu.IsFlagSet(Flags.Zero)); }, + /* LOOP Jb */ (cpu) => { return cpu.Loop(); }, + /* JCXZ */ (cpu) => { return cpu.JumpConditional(cpu.cx.Word == 0); }, + /* 0xE4 */ /* IN Ib AL */ (cpu) => { cpu.ax.Low = cpu.machine.ReadPort(cpu.ReadOpcodeIb()); return 6; }, + /* IN Ib AX */ (cpu) => { cpu.ax.Word = cpu.ReadPort16(cpu.ReadOpcodeIb()); return 6; }, + /* OUT Ib AL */ (cpu) => { cpu.machine.WritePort(cpu.ReadOpcodeIb(), cpu.ax.Low); return 6; }, + /* OUT Ib AX */ (cpu) => { cpu.WritePort16(cpu.ReadOpcodeIb(), cpu.ax.Word); return 6; }, + /* 0xE8 */ /* CALL Jv */ (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.Push(cpu.ip); cpu.ip += offset; return 4; }, + /* JMP Jv */ (cpu) => { var offset = cpu.ReadOpcodeIw(); cpu.ip += offset; return 3; }, + /* JMP Ap */ (cpu) => { var newIp = cpu.ReadOpcodeIw(); var newCs = cpu.ReadOpcodeIw(); cpu.ip = newIp; cpu.cs = newCs; return 5; }, + /* JMP Jb */ (cpu) => { cpu.ip = cpu.ReadOpcodeJb(); return 3; }, + /* 0xEC */ /* IN AL DX */ (cpu) => { cpu.ax.Low = cpu.machine.ReadPort(cpu.dx.Word); return 4; }, + /* IN AX DX */ (cpu) => { cpu.ax.Word = cpu.ReadPort16(cpu.dx.Word); return 4; }, + /* OUT DX AL */ (cpu) => { cpu.machine.WritePort(cpu.dx.Word, cpu.ax.Low); return 4; }, + /* OUT DX AX */ (cpu) => { cpu.WritePort16(cpu.dx.Word, cpu.ax.Word); return 4; }, + + /* 0xF0 */ /* (Prefix LOCK) */ (cpu) => 0, + /* (Invalid; NOP?) */ (cpu) => 3, + /* (Prefix REPNZ) */ (cpu) => 0, + /* (Prefix REPZ) */ (cpu) => 0, + /* 0xF4 */ /* HLT */ (cpu) => { cpu.halted = true; return 8; }, + /* CMC */ (cpu) => { cpu.SetClearFlagConditional(Flags.Carry, !cpu.IsFlagSet(Flags.Carry)); return 4; }, + /* GRP3 Eb */ Opcode0xF6, + /* GRP3 Ew */ Opcode0xF7, + /* 0xF8 */ /* CLC */ (cpu) => { cpu.ClearFlags(Flags.Carry); return 4; }, + /* STC */ (cpu) => { cpu.SetFlags(Flags.Carry); return 4; }, + /* CLI */ (cpu) => { cpu.ClearFlags(Flags.InterruptEnable); return 4; }, + /* STI */ (cpu) => { cpu.SetFlags(Flags.InterruptEnable); return 4; }, + /* 0xFC */ /* CLD */ (cpu) => { cpu.ClearFlags(Flags.Direction); return 4; }, + /* STD */ (cpu) => { cpu.SetFlags(Flags.Direction); return 4; }, + /* GRP4 Eb */ Opcode0xFE, + /* GRP4 Ew */ Opcode0xFF + }; + + private static int Opcode0x60(V30MZ cpu) + { + /* PUSHA */ + var oldSp = cpu.sp; + cpu.Push(cpu.ax.Word); + cpu.Push(cpu.cx.Word); + cpu.Push(cpu.dx.Word); + cpu.Push(cpu.bx.Word); + cpu.Push(oldSp); + cpu.Push(cpu.bp); + cpu.Push(cpu.si); + cpu.Push(cpu.di); + return 8; + } + + private static int Opcode0x61(V30MZ cpu) + { + /* POPA */ + cpu.di = cpu.Pop(); + cpu.si = cpu.Pop(); + cpu.bp = cpu.Pop(); + cpu.Pop(); /* don't restore SP */ + cpu.bx.Word = cpu.Pop(); + cpu.dx.Word = cpu.Pop(); + cpu.cx.Word = cpu.Pop(); + cpu.ax.Word = cpu.Pop(); + return 8; + } + + private static int Opcode0x62(V30MZ cpu) + { + /* BOUND Gw E */ + cpu.ReadModRM(); + var lo = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 0)); + var hi = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2)); + var reg = cpu.GetRegister16((RegisterNumber16)cpu.modRm.Mem); + if (reg < lo || reg > hi) cpu.Interrupt(5); + return 12; + } + + private static int Opcode0x6C(V30MZ cpu) + { + /* INSB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.InString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.InString(false); cycles += 5; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0x6D(V30MZ cpu) + { + /* INSW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.InString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.InString(true); cycles += 5; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0x6E(V30MZ cpu) + { + /* OUTSB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.OutString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.OutString(false); cycles += 6; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0x6F(V30MZ cpu) + { + /* OUTSW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.OutString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.OutString(true); cycles += 6; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0x80(V30MZ cpu) + { + /* GRP1 Eb Ib */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ADD */ cpu.WriteOpcodeEb(cpu.Add8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x1: /* OR */ cpu.WriteOpcodeEb(cpu.Or8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x2: /* ADC */ cpu.WriteOpcodeEb(cpu.Add8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x3: /* SBB */ cpu.WriteOpcodeEb(cpu.Sub8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x4: /* AND */ cpu.WriteOpcodeEb(cpu.And8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x5: /* SUB */ cpu.WriteOpcodeEb(cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x6: /* XOR */ cpu.WriteOpcodeEb(cpu.Xor8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x7: /* CMP */ cpu.Sub8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb()); cycles = 1; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0x81(V30MZ cpu) + { + /* GRP1 Ew Iw */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ADD */ cpu.WriteOpcodeEw(cpu.Add16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x1: /* OR */ cpu.WriteOpcodeEw(cpu.Or16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x2: /* ADC */ cpu.WriteOpcodeEw(cpu.Add16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x3: /* SBB */ cpu.WriteOpcodeEw(cpu.Sub16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x4: /* AND */ cpu.WriteOpcodeEw(cpu.And16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x5: /* SUB */ cpu.WriteOpcodeEw(cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x6: /* XOR */ cpu.WriteOpcodeEw(cpu.Xor16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw())); cycles = 1; break; + case 0x7: /* CMP */ cpu.Sub16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw()); cycles = 1; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0x83(V30MZ cpu) + { + /* GRP1 Ew Ib */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ADD */ cpu.WriteOpcodeEw(cpu.Add16(false, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x1: /* OR */ cpu.WriteOpcodeEw(cpu.Or16(cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x2: /* ADC */ cpu.WriteOpcodeEw(cpu.Add16(true, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x3: /* SBB */ cpu.WriteOpcodeEw(cpu.Sub16(true, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x4: /* AND */ cpu.WriteOpcodeEw(cpu.And16(cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x5: /* SUB */ cpu.WriteOpcodeEw(cpu.Sub16(false, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x6: /* XOR */ cpu.WriteOpcodeEw(cpu.Xor16(cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb())); cycles = 1; break; + case 0x7: /* CMP */ cpu.Sub16(false, cpu.ReadOpcodeEw(), (ushort)(sbyte)cpu.ReadOpcodeIb()); cycles = 1; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0x8D(V30MZ cpu) + { + /* LEA Gw M */ + cpu.ReadModRM(); + if (cpu.modRm.Mod != ModRM.Modes.Register) + { + cpu.WriteOpcodeGw(cpu.modRm.Offset); + } + return 8; + } + + private static int Opcode0x9A(V30MZ cpu) + { + /* CALL Ap */ + var newIp = cpu.ReadOpcodeIw(); + var newCs = cpu.ReadOpcodeIw(); + + cpu.Push(cpu.cs); + cpu.Push(cpu.ip); + + cpu.ip = newIp; + cpu.cs = newCs; + + return 9; + } + + private static int Opcode0x9E(V30MZ cpu) + { + /* SAHF */ + cpu.SetClearFlagConditional(Flags.Sign, ((Flags)cpu.ax.High & Flags.Sign) == Flags.Sign); + cpu.SetClearFlagConditional(Flags.Zero, ((Flags)cpu.ax.High & Flags.Zero) == Flags.Zero); + cpu.SetClearFlagConditional(Flags.Auxiliary, ((Flags)cpu.ax.High & Flags.Auxiliary) == Flags.Auxiliary); + cpu.SetClearFlagConditional(Flags.Parity, ((Flags)cpu.ax.High & Flags.Parity) == Flags.Parity); + cpu.SetClearFlagConditional(Flags.Carry, ((Flags)cpu.ax.High & Flags.Carry) == Flags.Carry); + return 4; + } + + private static int Opcode0xA4(V30MZ cpu) + { + /* MOVSB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.MoveString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.MoveString(false); cycles += 5; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0xA5(V30MZ cpu) + { + /* MOVSW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.MoveString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.MoveString(true); cycles += 5; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0xA6(V30MZ cpu) + { + /* CMPSB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.CompareString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.CompareString(false); cycles += 4; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero))); + } + return cycles; + } + + private static int Opcode0xA7(V30MZ cpu) + { + /* CMPSW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.CompareString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.CompareString(true); cycles += 4; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero))); + } + return cycles; + } + + private static int Opcode0xAA(V30MZ cpu) + { + /* STOSB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.StoreString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.StoreString(false); cycles += 2; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0xAB(V30MZ cpu) + { + /* STOSW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.StoreString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.StoreString(true); cycles += 2; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0xAC(V30MZ cpu) + { + /* LODSB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.LoadString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.LoadString(false); cycles += 2; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0xAD(V30MZ cpu) + { + /* LODSW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.LoadString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.LoadString(true); cycles += 2; } while (--cpu.cx.Word != 0); + } + return cycles; + } + + private static int Opcode0xAE(V30MZ cpu) + { + /* SCASB */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.ScanString(false); + else if (cpu.cx.Word != 0) + { + do { cpu.ScanString(false); cycles += 3; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero))); + } + return cycles; + } + + private static int Opcode0xAF(V30MZ cpu) + { + /* SCASW */ + var cycles = 5; + if (!cpu.prefixHasRepeat) + cpu.ScanString(true); + else if (cpu.cx.Word != 0) + { + do { cpu.ScanString(true); cycles += 3; } while (--cpu.cx.Word != 0 && (cpu.prefixRepeatOnNotEqual ? !cpu.IsFlagSet(Flags.Zero) : cpu.IsFlagSet(Flags.Zero))); + } + return cycles; + } + + private static int Opcode0xC0(V30MZ cpu) + { + /* GRP2 Eb Ib */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ROL */ cpu.WriteOpcodeEb(cpu.Rol8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x1: /* ROR */ cpu.WriteOpcodeEb(cpu.Ror8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x2: /* RCL */ cpu.WriteOpcodeEb(cpu.Rol8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x3: /* RCR */ cpu.WriteOpcodeEb(cpu.Ror8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x4: /* SHL */ cpu.WriteOpcodeEb(cpu.Shl8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x5: /* SHR */ cpu.WriteOpcodeEb(cpu.Shr8(false, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x6: /* --- */ cycles = 3; break; + case 0x7: /* SAR */ cpu.WriteOpcodeEb(cpu.Shr8(true, cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb())); cycles = 3; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xC1(V30MZ cpu) + { + /* GRP2 Ew Ib */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ROL */ cpu.WriteOpcodeEw(cpu.Rol16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x1: /* ROR */ cpu.WriteOpcodeEw(cpu.Ror16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x2: /* RCL */ cpu.WriteOpcodeEw(cpu.Rol16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x3: /* RCR */ cpu.WriteOpcodeEw(cpu.Ror16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x4: /* SHL */ cpu.WriteOpcodeEw(cpu.Shl16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x5: /* SHR */ cpu.WriteOpcodeEw(cpu.Shr16(false, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + case 0x6: /* --- */ cycles = 3; break; + case 0x7: /* SAR */ cpu.WriteOpcodeEw(cpu.Shr16(true, cpu.ReadOpcodeEw(), cpu.ReadOpcodeIb())); cycles = 3; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xC4(V30MZ cpu) + { + /* LES Gw Mp */ + cpu.ReadModRM(); + if (cpu.modRm.Mod != ModRM.Modes.Register) + { + cpu.WriteOpcodeGw(cpu.ReadOpcodeEw()); + cpu.es = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2)); + } + return 8; + } + + private static int Opcode0xC5(V30MZ cpu) + { + /* LDS Gw Mp */ + cpu.ReadModRM(); + if (cpu.modRm.Mod != ModRM.Modes.Register) + { + cpu.WriteOpcodeGw(cpu.ReadOpcodeEw()); + cpu.ds = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2)); + } + return 8; + } + + private static int Opcode0xC8(V30MZ cpu) + { + /* ENTER */ + var offset = cpu.ReadOpcodeIw(); + var length = (byte)(cpu.ReadOpcodeIb() & 0x1F); + + cpu.Push(cpu.bp); + cpu.bp = cpu.sp; + cpu.sp -= offset; + + if (length != 0) + { + for (var i = 1; i < length; i++) + cpu.Push(cpu.ReadMemory16(cpu.ss, (ushort)(cpu.bp - i * 2))); + cpu.Push(cpu.bp); + } + return 7; + } + + private static int Opcode0xD0(V30MZ cpu) + { + /* GRP2 Eb 1 */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ROL */ cpu.WriteOpcodeEb(cpu.Rol8(false, cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + case 0x1: /* ROR */ cpu.WriteOpcodeEb(cpu.Ror8(false, cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + case 0x2: /* RCL */ cpu.WriteOpcodeEb(cpu.Rol8(true, cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + case 0x3: /* RCR */ cpu.WriteOpcodeEb(cpu.Ror8(true, cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + case 0x4: /* SHL */ cpu.WriteOpcodeEb(cpu.Shl8(cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + case 0x5: /* SHR */ cpu.WriteOpcodeEb(cpu.Shr8(false, cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + case 0x6: /* --- */ cycles = 3; break; + case 0x7: /* SAR */ cpu.WriteOpcodeEb(cpu.Shr8(true, cpu.ReadOpcodeEb(), 1)); cycles = 1; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xD1(V30MZ cpu) + { + /* GRP2 Ew 1 */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ROL */ cpu.WriteOpcodeEw(cpu.Rol16(false, cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + case 0x1: /* ROR */ cpu.WriteOpcodeEw(cpu.Ror16(false, cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + case 0x2: /* RCL */ cpu.WriteOpcodeEw(cpu.Rol16(true, cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + case 0x3: /* RCR */ cpu.WriteOpcodeEw(cpu.Ror16(true, cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + case 0x4: /* SHL */ cpu.WriteOpcodeEw(cpu.Shl16(cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + case 0x5: /* SHR */ cpu.WriteOpcodeEw(cpu.Shr16(false, cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + case 0x6: /* --- */ cycles = 3; break; + case 0x7: /* SAR */ cpu.WriteOpcodeEw(cpu.Shr16(true, cpu.ReadOpcodeEw(), 1)); cycles = 1; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xD2(V30MZ cpu) + { + /* GRP2 Eb CL */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ROL */ cpu.WriteOpcodeEb(cpu.Rol8(false, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + case 0x1: /* ROR */ cpu.WriteOpcodeEb(cpu.Ror8(false, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + case 0x2: /* RCL */ cpu.WriteOpcodeEb(cpu.Rol8(true, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + case 0x3: /* RCR */ cpu.WriteOpcodeEb(cpu.Ror8(true, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + case 0x4: /* SHL */ cpu.WriteOpcodeEb(cpu.Shl8(cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + case 0x5: /* SHR */ cpu.WriteOpcodeEb(cpu.Shr8(false, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + case 0x6: /* --- */ cycles = 3; break; + case 0x7: /* SAR */ cpu.WriteOpcodeEb(cpu.Shr8(true, cpu.ReadOpcodeEb(), cpu.cx.Low)); cycles = 3; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xD3(V30MZ cpu) + { + /* GRP2 Ew CL */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* ROL */ cpu.WriteOpcodeEw(cpu.Rol16(false, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + case 0x1: /* ROR */ cpu.WriteOpcodeEw(cpu.Ror16(false, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + case 0x2: /* RCL */ cpu.WriteOpcodeEw(cpu.Rol16(true, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + case 0x3: /* RCR */ cpu.WriteOpcodeEw(cpu.Ror16(true, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + case 0x4: /* SHL */ cpu.WriteOpcodeEw(cpu.Shl16(cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + case 0x5: /* SHR */ cpu.WriteOpcodeEw(cpu.Shr16(false, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + case 0x6: /* --- */ cycles = 3; break; + case 0x7: /* SAR */ cpu.WriteOpcodeEw(cpu.Shr16(true, cpu.ReadOpcodeEw(), cpu.cx.Low)); cycles = 3; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + /* NOTE: AAM/AAD: While NEC V20/V30 do ignore immediate & always use base 10 (1), V30MZ does *not* ignore the immediate (2) + * (1): https://www.vcfed.org/forum/forum/technical-support/vintage-computer-programming/36551/ + * (2): https://github.com/xdanieldzd/StoicGoose/issues/9 + */ + + private static int Opcode0xD4(V30MZ cpu) + { + /* AAM */ + var value = cpu.ReadOpcodeIb(); + if (value == 0) + { + /* Division-by-zero exception */ + cpu.Interrupt(0); + } + else + { + cpu.ax.High = (byte)(cpu.ax.Low / value); + cpu.ax.Low = (byte)(cpu.ax.Low % value); + cpu.SetClearFlagConditional(Flags.Parity, CalculateParity(cpu.ax.Low)); + cpu.SetClearFlagConditional(Flags.Zero, (cpu.ax.Word & 0xFFFF) == 0); + cpu.SetClearFlagConditional(Flags.Sign, (cpu.ax.Word & 0x8000) != 0); + } + return 16; + } + + private static int Opcode0xD5(V30MZ cpu) + { + /* AAD */ + var value = cpu.ReadOpcodeIb(); + cpu.ax.Low = (byte)(cpu.ax.High * value + cpu.ax.Low); + cpu.ax.High = 0; + cpu.SetClearFlagConditional(Flags.Parity, CalculateParity(cpu.ax.Low)); + cpu.SetClearFlagConditional(Flags.Zero, (cpu.ax.Word & 0xFFFF) == 0); + cpu.SetClearFlagConditional(Flags.Sign, (cpu.ax.Word & 0x8000) != 0); + return 6; + } + + private static int Opcode0xF6(V30MZ cpu) + { + /* GRP3 Eb */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* TEST */ cpu.And8(cpu.ReadOpcodeEb(), cpu.ReadOpcodeIb()); cycles = 1; break; + case 0x1: /* --- */ cycles = 3; break; + case 0x2: /* NOT */ cpu.WriteOpcodeEb((byte)~cpu.ReadOpcodeEb()); cycles = 1; break; + case 0x3: /* NEG */ cpu.WriteOpcodeEb(cpu.Neg8(cpu.ReadOpcodeEb())); cycles = 1; break; + case 0x4: /* MUL */ cpu.ax.Word = cpu.Mul8(false, cpu.ax.Low, cpu.ReadOpcodeEb()); cycles = 3; break; + case 0x5: /* IMUL */ cpu.ax.Word = cpu.Mul8(true, cpu.ax.Low, cpu.ReadOpcodeEb()); cycles = 3; break; + case 0x6: /* DIV */ cpu.ax.Word = cpu.Div8(false, cpu.ax.Word, cpu.ReadOpcodeEb()); cycles = 15; break; + case 0x7: /* IDIV */ cpu.ax.Word = cpu.Div8(true, cpu.ax.Word, cpu.ReadOpcodeEb()); cycles = 17; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xF7(V30MZ cpu) + { + /* GRP3 Ew */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* TEST */ cpu.And16(cpu.ReadOpcodeEw(), cpu.ReadOpcodeIw()); cycles = 1; break; + case 0x1: /* --- */ cycles = 3; break; + case 0x2: /* NOT */ cpu.WriteOpcodeEw((ushort)~cpu.ReadOpcodeEw()); cycles = 1; break; + case 0x3: /* NEG */ cpu.WriteOpcodeEw(cpu.Neg16(cpu.ReadOpcodeEw())); cycles = 1; break; + case 0x4: /* MUL */ { var result = cpu.Mul16(false, cpu.ax.Word, cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 3; } break; + case 0x5: /* IMUL */ { var result = cpu.Mul16(true, cpu.ax.Word, cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 3; } break; + case 0x6: /* DIV */ { var result = cpu.Div16(false, (uint)(cpu.dx.Word << 16 | cpu.ax.Word), cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 23; } break; + case 0x7: /* IDIV */ { var result = cpu.Div16(true, (uint)(cpu.dx.Word << 16 | cpu.ax.Word), cpu.ReadOpcodeEw()); cpu.dx.Word = (ushort)((result >> 16) & 0xFFFF); cpu.ax.Word = (ushort)((result >> 0) & 0xFFFF); cycles = 24; } break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xFE(V30MZ cpu) + { + /* GRP4 Eb */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* INC */ cpu.WriteOpcodeEb(cpu.Inc8(cpu.ReadOpcodeEb())); cycles = 1; break; + case 0x1: /* DEC */ cpu.WriteOpcodeEb(cpu.Dec8(cpu.ReadOpcodeEb())); cycles = 1; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + + private static int Opcode0xFF(V30MZ cpu) + { + /* GRP4 Ew */ + int cycles; + cpu.ReadModRM(); + switch (cpu.modRm.Reg) + { + case 0x0: /* INC */ cpu.WriteOpcodeEw(cpu.Inc16(cpu.ReadOpcodeEw())); cycles = 1; break; + case 0x1: /* DEC */ cpu.WriteOpcodeEw(cpu.Dec16(cpu.ReadOpcodeEw())); cycles = 1; break; + case 0x2: /* CALL */ + { + var offset = cpu.ReadOpcodeEw(); + cpu.Push(cpu.ip); + cpu.ip = offset; + cycles = 5; + } + break; + case 0x3: /* CALL Mp */ + { + if (cpu.modRm.Mod != ModRM.Modes.Register) + { + var offset = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 0)); + var segment = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2)); + cpu.Push(cpu.cs); + cpu.Push(cpu.ip); + cpu.cs = segment; + cpu.ip = offset; + } + cycles = 11; + } + break; + case 0x4: /* JMP */ cpu.ip = cpu.ReadOpcodeEw(); cycles = 4; break; + case 0x5: /* JMP Mp */ + { + if (cpu.modRm.Mod != ModRM.Modes.Register) + { + cpu.ip = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 0)); + cpu.cs = cpu.ReadMemory16(cpu.modRm.Segment, (ushort)(cpu.modRm.Offset + 2)); + } + cycles = 9; + } + break; + case 0x6: /* PUSH */ cpu.Push(cpu.ReadOpcodeEw()); cycles = 3; break; + case 0x7: /* --- */ cycles = 3; break; + default: throw new Exception("Invalid opcode"); + } + return cycles; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs.meta new file mode 100644 index 0000000..038ed7c --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.OpcodeTable.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7f721c42886f2904c9a7eda1c94b6d14 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs new file mode 100644 index 0000000..053e42c --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs @@ -0,0 +1,71 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + SegmentNumber prefixSegOverride; + bool prefixHasRepeat; + bool prefixRepeatOnNotEqual; + + private void ResetPrefixes() + { + prefixSegOverride = SegmentNumber.Unset; + prefixHasRepeat = false; + prefixRepeatOnNotEqual = false; + } + + private bool HandlePrefixes(byte op) + { + var isOpcode = true; + + switch (op) + { + /* Prefixes */ + case 0x26: + /* :ES */ + prefixSegOverride = SegmentNumber.ES; + isOpcode = false; + break; + + case 0x2E: + /* :CS */ + prefixSegOverride = SegmentNumber.CS; + isOpcode = false; + break; + + case 0x36: + /* :SS */ + prefixSegOverride = SegmentNumber.SS; + isOpcode = false; + break; + + case 0x3E: + /* :DS */ + prefixSegOverride = SegmentNumber.DS; + isOpcode = false; + break; + + case 0xF0: + /* LOCK */ + //TODO: implement?? + isOpcode = false; + break; + + case 0xF2: + /* REPNE */ + prefixHasRepeat = true; + prefixRepeatOnNotEqual = true; + isOpcode = false; + break; + + case 0xF3: + /* REP/REPE */ + prefixHasRepeat = true; + prefixRepeatOnNotEqual = false; + isOpcode = false; + break; + } + + return isOpcode; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs.meta new file mode 100644 index 0000000..fa2df8f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Prefixes.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dff52160b1aa55c48a07722be9d654ff \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs new file mode 100644 index 0000000..64de581 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs @@ -0,0 +1,111 @@ +using System; +using System.Runtime.InteropServices; + +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + enum RegisterNumber8 : byte + { + AL = 0b000, + CL = 0b001, + DL = 0b010, + BL = 0b011, + AH = 0b100, + CH = 0b101, + DH = 0b110, + BH = 0b111 + } + + enum RegisterNumber16 : byte + { + AX = 0b000, + CX = 0b001, + DX = 0b010, + BX = 0b011, + SP = 0b100, + BP = 0b101, + SI = 0b110, + DI = 0b111 + } + + private byte GetRegister8(RegisterNumber8 reg) + { + return reg switch + { + RegisterNumber8.AL => ax.Low, + RegisterNumber8.CL => cx.Low, + RegisterNumber8.DL => dx.Low, + RegisterNumber8.BL => bx.Low, + RegisterNumber8.AH => ax.High, + RegisterNumber8.CH => cx.High, + RegisterNumber8.DH => dx.High, + RegisterNumber8.BH => bx.High, + _ => throw new ArgumentException("Invalid register", nameof(reg)), + }; + } + + private ushort GetRegister16(RegisterNumber16 reg) + { + return reg switch + { + RegisterNumber16.AX => ax.Word, + RegisterNumber16.CX => cx.Word, + RegisterNumber16.DX => dx.Word, + RegisterNumber16.BX => bx.Word, + RegisterNumber16.SP => sp, + RegisterNumber16.BP => bp, + RegisterNumber16.SI => si, + RegisterNumber16.DI => di, + _ => throw new ArgumentException("Invalid register", nameof(reg)), + }; + } + + private void SetRegister8(RegisterNumber8 reg, byte value) + { + switch (reg) + { + case RegisterNumber8.AL: ax.Low = value; break; + case RegisterNumber8.CL: cx.Low = value; break; + case RegisterNumber8.DL: dx.Low = value; break; + case RegisterNumber8.BL: bx.Low = value; break; + case RegisterNumber8.AH: ax.High = value; break; + case RegisterNumber8.CH: cx.High = value; break; + case RegisterNumber8.DH: dx.High = value; break; + case RegisterNumber8.BH: bx.High = value; break; + default: throw new ArgumentException("Invalid register", nameof(reg)); + } + } + + private void SetRegister16(RegisterNumber16 reg, ushort value) + { + switch (reg) + { + case RegisterNumber16.AX: ax.Word = value; break; + case RegisterNumber16.CX: cx.Word = value; break; + case RegisterNumber16.DX: dx.Word = value; break; + case RegisterNumber16.BX: bx.Word = value; break; + case RegisterNumber16.SP: sp = value; break; + case RegisterNumber16.BP: bp = value; break; + case RegisterNumber16.SI: si = value; break; + case RegisterNumber16.DI: di = value; break; + default: throw new ArgumentException("Invalid register", nameof(reg)); + } + } + + [StructLayout(LayoutKind.Explicit)] + public struct Register16 + { + [FieldOffset(0)] + public byte Low; + [FieldOffset(1)] + public byte High; + + [FieldOffset(0)] + public ushort Word; + + public static implicit operator Register16(ushort value) => new() { Word = value }; + + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs.meta new file mode 100644 index 0000000..95761e1 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Registers.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a4d62a2a12b27744ea0c51ed3e7a2500 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs new file mode 100644 index 0000000..d16710a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs @@ -0,0 +1,45 @@ +using System; + +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + enum SegmentNumber : byte + { + ES = 0b00, + CS = 0b01, + SS = 0b10, + DS = 0b11, + Unset = 0xFF + } + + private ushort GetSegment(SegmentNumber seg) + { + return seg switch + { + SegmentNumber.ES => es, + SegmentNumber.CS => cs, + SegmentNumber.SS => ss, + SegmentNumber.DS => ds, + _ => throw new ArgumentException("Invalid segment", nameof(seg)), + }; + } + + private void SetSegment(SegmentNumber seg, ushort value) + { + switch (seg) + { + case SegmentNumber.ES: es = value; break; + case SegmentNumber.CS: cs = value; break; + case SegmentNumber.SS: ss = value; break; + case SegmentNumber.DS: ds = value; break; + default: throw new ArgumentException("Invalid segment", nameof(seg)); + } + } + + private ushort GetSegmentViaOverride(SegmentNumber seg) + { + return GetSegment(prefixSegOverride != SegmentNumber.Unset ? prefixSegOverride : seg); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs.meta new file mode 100644 index 0000000..153ca8b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Segments.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f05e782fc3972e146a5970e63968477a \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs new file mode 100644 index 0000000..d6d6d6d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs @@ -0,0 +1,104 @@ +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ + { + private static int GetIncrement(bool is16Bit, bool isDirectionFlagSet) + { + return isDirectionFlagSet ? (is16Bit ? -2 : -1) : (is16Bit ? 2 : 1); + } + + private void InString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + if (!is16Bit) + WriteMemory8(es, di, machine.ReadPort(dx.Word)); + else + WriteMemory16(es, di, ReadPort16(dx.Word)); + + di = (ushort)(di + increment); + } + + private void OutString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + var temp = GetSegmentViaOverride(SegmentNumber.DS); + + if (!is16Bit) + machine.WritePort(dx.Word, ReadMemory8(temp, si)); + else + WritePort16(dx.Word, ReadMemory16(temp, si)); + + si = (ushort)(si + increment); + } + + private void MoveString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + var temp = GetSegmentViaOverride(SegmentNumber.DS); + + if (!is16Bit) + WriteMemory8(es, di, ReadMemory8(temp, si)); + else + WriteMemory16(es, di, ReadMemory16(temp, si)); + + di = (ushort)(di + increment); + si = (ushort)(si + increment); + } + + private void CompareString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + var temp = GetSegmentViaOverride(SegmentNumber.DS); + + if (!is16Bit) + Sub8(false, ReadMemory8(temp, si), ReadMemory8(es, di)); + else + Sub16(false, ReadMemory16(temp, si), ReadMemory16(es, di)); + + di = (ushort)(di + increment); + si = (ushort)(si + increment); + } + + private void StoreString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + if (!is16Bit) + WriteMemory8(es, di, ax.Low); + else + WriteMemory16(es, di, ax.Word); + + di = (ushort)(di + increment); + } + + private void LoadString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + var temp = GetSegmentViaOverride(SegmentNumber.DS); + + if (!is16Bit) + ax.Low = ReadMemory8(temp, si); + else + ax.Word = ReadMemory16(temp, si); + + si = (ushort)(si + increment); + } + + private void ScanString(bool is16Bit) + { + var increment = GetIncrement(is16Bit, IsFlagSet(Flags.Direction)); + + if (!is16Bit) + Sub8(false, ax.Low, ReadMemory8(es, di)); + else + Sub16(false, ax.Word, ReadMemory16(es, di)); + + di = (ushort)(di + increment); + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs.meta new file mode 100644 index 0000000..059b3c6 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.Strings.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 43c1a3a659adfb244be70cdc0ded4be7 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs new file mode 100644 index 0000000..4a80ff2 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs @@ -0,0 +1,139 @@ +using StoicGoose.Core.Interfaces; + +namespace StoicGoose.Core.CPU +{ + public sealed partial class V30MZ : IComponent + { + // TODO: attempt prefetch emulation (Meitantei Conan - Nishi no Meitantei Saidai no Kiki; cart changes banks on startup, can no longer execute jump, execs garbage) + + /* Parent machine instance */ + readonly IMachine machine = default; + + /* General registers */ + Register16 ax, bx, cx, dx; + ushort sp, bp, si, di; + /* Segment registers */ + ushort cs, ds, ss, es; + /* Status and instruction registers */ + ushort ip; + Flags flags; + + bool halted; + int opCycles, intCycles; + + /* Public properties for registers */ + public Register16 AX { get => ax; set => ax = value; } + public Register16 BX { get => bx; set => bx = value; } + public Register16 CX { get => cx; set => cx = value; } + public Register16 DX { get => dx; set => dx = value; } + public ushort SP { get => sp; set => sp = value; } + public ushort BP { get => bp; set => bp = value; } + public ushort SI { get => si; set => si = value; } + public ushort DI { get => di; set => di = value; } + public ushort CS { get => cs; set => cs = value; } + public ushort DS { get => ds; set => ds = value; } + public ushort SS { get => ss; set => ss = value; } + public ushort ES { get => es; set => es = value; } + public ushort IP { get => ip; set => ip = value; } + + public bool IsHalted { get => halted; set => halted = value; } + + public V30MZ(IMachine machine) + { + this.machine = machine; + + Reset(); + } + + public void Reset() + { + /* CPU reset */ + flags = Flags.ReservedB1 | Flags.ReservedB12 | Flags.ReservedB13 | Flags.ReservedB14 | Flags.ReservedB15; + ip = 0x0000; + cs = 0xFFFF; + ds = 0x0000; + ss = 0x0000; + es = 0x0000; + + /* Initialized by WS bootstrap */ + ax.Word = 0x0000; + dx.Word = 0x0000; + bp = 0x0000; + ss = 0x0000; + sp = 0x2000; + ds = 0x0000; + es = 0x0000; + + /* Misc variables */ + halted = false; + opCycles = intCycles = 0; + + ResetPrefixes(); + modRm.Reset(); + } + + public void Shutdown() + { + // + } + + public void Interrupt(int vector) + { + /* Resume execution */ + halted = false; + + /* Read interrupt handler's segment & offset */ + var offset = ReadMemory16(0, (ushort)((vector * 4) + 0)); + var segment = ReadMemory16(0, (ushort)((vector * 4) + 2)); + + /* Push state, clear flags, etc. */ + Push((ushort)flags); + Push(cs); + Push(ip); + + ClearFlags(Flags.InterruptEnable); + ClearFlags(Flags.Trap); + + ResetPrefixes(); + modRm.Reset(); + + intCycles = 32; + + /* Continue with interrupt handler */ + cs = segment; + ip = offset; + } + + public int Step() + { + var cycles = 0; + + if (halted) + { + /* CPU is halted */ + cycles++; + } + else + { + /* Read any prefixes & opcode */ + byte opcode; + while (!HandlePrefixes(opcode = ReadMemory8(cs, ip++))) { } + + /* Execute instruction */ + opCycles = instructions[opcode](this); + + cycles += opCycles; + opCycles = 0; + } + + cycles += intCycles; + intCycles = 0; + + /* Reset state for next instruction */ + ResetPrefixes(); + modRm.Reset(); + + return cycles; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs.meta new file mode 100644 index 0000000..814b3b4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/CPU/V30MZ.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 946e7f92ed1c35e45bd71bbcd108695c \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges.meta new file mode 100644 index 0000000..9d45074 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4878ed813b76a834abf448a6d1c96295 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs new file mode 100644 index 0000000..4ab958f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs @@ -0,0 +1,248 @@ +using System; + +using StoicGoose.Common.Utilities; +using StoicGoose.Core.EEPROMs; +using StoicGoose.Core.Interfaces; + +namespace StoicGoose.Core.Cartridges +{ + public class Cartridge : IComponent + { + byte[] rom, sram; + uint romMask, sramMask; + + Metadata metadata; + + /* REG_BANK_xxx */ + byte romBank2, sramBank, romBank0, romBank1; + + /* REG_EEP_xxx -> EEPROM class */ + EEPROM eeprom = default; + + /* REG_RTC_xxx -> RTC class */ + RTC rtc = default; + + public bool IsLoaded => rom?.Length > 0; + public int SizeInBytes => rom?.Length ?? 0; + public uint Crc32 { get; private set; } = default; + + public Metadata Metadata => metadata; + + public Cartridge() + { + rom = Array.Empty(); + sram = Array.Empty(); + } + + public void Reset() + { + romBank2 = 0xFF; + sramBank = 0xFF; + romBank0 = 0xFF; + romBank1 = 0xFF; + + eeprom?.Reset(); + rtc?.Reset(); + + // HACK: set RTC to current date/time on boot for testing + rtc?.Program(DateTime.Now); + } + + public void Shutdown() + { + eeprom?.Shutdown(); + rtc?.Shutdown(); + } + + public void LoadRom(byte[] data) + { + rom = data; + romMask = (uint)(rom.Length - 1); + + metadata = new Metadata(rom); + + if (metadata.SaveSize != 0) + { + if (metadata.IsSramSave) + { + sram = new byte[metadata.SaveSize]; + sramMask = (uint)(sram.Length - 1); + } + else if (metadata.IsEepromSave) + { + switch (metadata.SaveType) + { + // TODO: verify size/address bits + case Metadata.SaveTypes.Eeprom1Kbit: eeprom = new EEPROM(metadata.SaveSize, 6); break; + case Metadata.SaveTypes.Eeprom16Kbit: eeprom = new EEPROM(metadata.SaveSize, 10); break; + case Metadata.SaveTypes.Eeprom8Kbit: eeprom = new EEPROM(metadata.SaveSize, 9); break; + } + } + } + + if (metadata.IsRtcPresent) + { + // NOTE: "RTC present" flag is not entirely consistent; ex. Digimon Tamers Battle Spirit has the flag, but does not have an RTC + rtc = new RTC(); + } + + Crc32 = Common.Utilities.Crc32.Calculate(rom); + + Log.WriteEvent(LogSeverity.Information, this, "ROM loaded."); + Log.WriteLine($"~ {Ansi.Cyan}Cartridge metadata{Ansi.Reset} ~"); + Log.WriteLine($" Publisher ID: {Metadata.PublisherCode}, {Metadata.PublisherName} [0x{Metadata.PublisherId:X2}]"); + Log.WriteLine($" System type: {Metadata.SystemType}"); + Log.WriteLine($" Game ID: 0x{Metadata.GameId:X2}"); + Log.WriteLine($" Calculated ID string: {Metadata.GameIdString}"); + Log.WriteLine($" Game revision: 0x{Metadata.GameRevision:X2}"); + Log.WriteLine($" ROM size: {Metadata.RomSize} [0x{(byte)Metadata.RomSize:X2}]"); + Log.WriteLine($" Save type/size: {Metadata.SaveType}/{Metadata.SaveSize} [0x{(byte)Metadata.SaveType:X2}]"); + Log.WriteLine($" Misc flags: 0x{Metadata.MiscFlags:X2}"); + Log.WriteLine($" Orientation: {Metadata.Orientation}"); + Log.WriteLine($" ROM bus width: {Metadata.RomBusWidth}"); + Log.WriteLine($" ROM access speed: {Metadata.RomAccessSpeed}"); + Log.WriteLine($" RTC present: {Metadata.IsRtcPresent} [0x{Metadata.RtcPresentFlag:X2}]"); + Log.WriteLine($" Checksum (from metadata): 0x{Metadata.Checksum:X4}"); + Log.WriteLine($" Checksum (calculated): 0x{Metadata.CalculatedChecksum:X4}"); + Log.WriteLine($" Checksum is {(metadata.IsChecksumValid ? $"{Ansi.Green}valid" : $"{Ansi.Red}invalid")}{Ansi.Reset}!"); + + if (metadata.PublisherId == 0x01 && metadata.GameId == 0x27) + { + // HACK: Meitantei Conan - Nishi no Meitantei Saidai no Kiki, prevent crash on startup (see TODO in V30MZ, prefetching) + rom[0xFFFE8] = 0xEA; + rom[0xFFFE9] = 0x00; + rom[0xFFFEA] = 0x00; + rom[0xFFFEB] = 0x00; + rom[0xFFFEC] = 0x20; + Log.WriteLine($"~ {Ansi.Red}Conan prefetch hack enabled{Ansi.Reset} ~"); + } + } + + public void LoadSram(byte[] data) + { + if (data.Length != sram.Length) throw new Exception("Sram size mismatch"); + Buffer.BlockCopy(data, 0, sram, 0, data.Length); + } + + public void LoadEeprom(byte[] data) + { + eeprom?.LoadContents(data); + } + + public byte[] GetSram() + { + return sram.Clone() as byte[]; + } + + public byte[] GetEeprom() + { + return eeprom?.GetContents().Clone() as byte[]; + } + + public bool Step(int clockCyclesInStep) + { + return rtc != null && rtc.Step(clockCyclesInStep); + } + + public byte ReadMemory(uint address) + { + return address switch + { + /* SRAM */ + var n when n >= 0x010000 && n < 0x020000 && sram.Length != 0 => sram[((uint)(sramBank << 16) | (address & 0x0FFFF)) & sramMask], + /* ROM bank 0 */ + var n when n >= 0x020000 && n < 0x030000 && rom.Length != 0 => rom[((uint)(romBank0 << 16) | (address & 0x0FFFF)) & romMask], + /* ROM bank 1 */ + var n when n >= 0x030000 && n < 0x040000 && rom.Length != 0 => rom[((uint)(romBank1 << 16) | (address & 0x0FFFF)) & romMask], + /* ROM bank 2 */ + var n when n >= 0x040000 && n < 0x100000 && rom.Length != 0 => rom[((uint)(romBank2 << 20) | (address & 0xFFFFF)) & romMask], + /* Unmapped */ + _ => 0x90, + }; + } + + public void WriteMemory(uint address, byte value) + { + /* SRAM */ + if (address >= 0x010000 && address < 0x020000 && sram.Length != 0) + sram[((uint)(sramBank << 16) | (address & 0x0FFFF)) & sramMask] = value; + } + + public byte ReadPort(ushort port) + { + return port switch + { + /* REG_BANK_ROM2 */ + 0xC0 => romBank2, + /* REG_BANK_SRAM */ + 0xC1 => sramBank, + /* REG_BANK_ROM0 */ + 0xC2 => romBank0, + /* REG_BANK_ROM1 */ + 0xC3 => romBank1, + /* REG_EEP_DATA (low) */ + 0xC4 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90, + /* REG_EEP_DATA (high) */ + 0xC5 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90, + /* REG_EEP_ADDR (low) */ + 0xC6 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90, + /* REG_EEP_ADDR (high) */ + 0xC7 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90, + /* REG_EEP_STATUS (read) */ + 0xC8 => eeprom != null ? eeprom.ReadPort((byte)(port - 0xC4)) : (byte)0x90, + /* REG_RTC_STATUS (read) */ + 0xCA => rtc != null ? rtc.ReadPort((byte)(port - 0xCA)) : (byte)0x90, + /* REG_RTC_DATA */ + 0xCB => rtc != null ? rtc.ReadPort((byte)(port - 0xCA)) : (byte)0x90, + /* Unmapped */ + _ => 0x90, + }; + } + + public void WritePort(ushort port, byte value) + { + switch (port) + { + case 0xC0: + /* REG_BANK_ROM2 */ + romBank2 = value; + break; + + case 0xC1: + /* REG_BANK_SRAM */ + sramBank = value; + break; + + case 0xC2: + /* REG_BANK_ROM0 */ + romBank0 = value; + break; + + case 0xC3: + /* REG_BANK_ROM1 */ + romBank1 = value; + break; + + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + /* REG_EEP_DATA (low) */ + /* REG_EEP_DATA (high) */ + /* REG_EEP_ADDR (low) */ + /* REG_EEP_ADDR (high) */ + /* REG_EEP_CMD (write) */ + eeprom?.WritePort((byte)(port - 0xC4), value); + break; + + case 0xCA: + case 0xCB: + /* REG_RTC_CMD (write) */ + /* REG_RTC_DATA */ + rtc?.WritePort((byte)(port - 0xCA), value); + break; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs.meta new file mode 100644 index 0000000..fc5cb3d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Cartridge.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4de2597a945e9a14082b644bcddf3e4e \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs new file mode 100644 index 0000000..b373712 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs @@ -0,0 +1,171 @@ +using System.Collections.Generic; + +namespace StoicGoose.Core.Cartridges +{ + public class Metadata + { + public enum SystemTypes : byte + { + WonderSwan = 0x00, + WonderSwanColor = 0x01 + } + + public enum RomSizes : byte + { + Rom1Mbit = 0x00, // ??? + Rom2Mbit = 0x01, // ??? + Rom4Mbit = 0x02, + Rom8Mbit = 0x03, + Rom16Mbit = 0x04, + Rom24Mbit = 0x05, + Rom32Mbit = 0x06, + Rom48Mbit = 0x07, + Rom64Mbit = 0x08, + Rom128Mbit = 0x09 + } + + public enum SaveTypes : byte + { + None = 0x00, + Sram64Kbit = 0x01, + Sram256Kbit = 0x02, + Sram1Mbit = 0x03, + Sram2Mbit = 0x04, + Sram4Mbit = 0x05, + Eeprom1Kbit = 0x10, + Eeprom16Kbit = 0x20, + Eeprom8Kbit = 0x50 //??? + } + + public enum Orientations : byte + { + Horizontal = 0 << 0, + Vertical = 1 << 0, + } + + public enum RomBusWidths : byte + { + Width16Bit = 0 << 1, + Width8Bit = 1 << 1, + } + + public enum RomAccessSpeeds : byte + { + Speed3Cycle = 0 << 2, + Speed1Cycle = 1 << 2 + } + + readonly Dictionary publishers = new() + { + { 0x00, ("???", "Misc. (invalid)") }, + { 0x01, ("BAN", "Bandai") }, + { 0x02, ("TAT", "Taito") }, + { 0x03, ("TMY", "Tomy") }, + { 0x04, ("KEX", "Koei") }, + { 0x05, ("DTE", "Data East") }, + { 0x06, ("AAE", "Asmik Ace") }, + { 0x07, ("MDE", "Media Entertainment") }, + { 0x08, ("NHB", "Nichibutsu") }, + { 0x0A, ("CCJ", "Coconuts Japan") }, + { 0x0B, ("SUM", "Sammy") }, + { 0x0C, ("SUN", "Sunsoft") }, + { 0x0D, ("PAW", "Mebius (?)") }, + { 0x0E, ("BPR", "Banpresto") }, + { 0x10, ("JLC", "Jaleco") }, + { 0x11, ("MGA", "Imagineer") }, + { 0x12, ("KNM", "Konami") }, + { 0x16, ("KBS", "Kobunsha") }, + { 0x17, ("BTM", "Bottom Up") }, + { 0x18, ("KGT", "Kaga Tech") }, + { 0x19, ("SRV", "Sunrise") }, + { 0x1A, ("CFT", "Cyber Front") }, + { 0x1B, ("MGH", "Mega House") }, + { 0x1D, ("BEC", "Interbec") }, + { 0x1E, ("NAP", "Nihon Application") }, + { 0x1F, ("BVL", "Bandai Visual") }, + { 0x20, ("ATN", "Athena") }, + { 0x21, ("KDX", "KID") }, + { 0x22, ("HAL", "HAL Corporation") }, + { 0x23, ("YKE", "Yuki Enterprise") }, + { 0x24, ("OMM", "Omega Micott") }, + { 0x25, ("LAY", "Layup") }, + { 0x26, ("KDK", "Kadokawa Shoten") }, + { 0x27, ("SHL", "Shall Luck") }, + { 0x28, ("SQR", "Squaresoft") }, + { 0x2A, ("SCC", "NTT DoCoMo (?)") }, /* MobileWonderGate */ + { 0x2B, ("TMC", "Tom Create") }, + { 0x2D, ("NMC", "Namco") }, + { 0x2E, ("SES", "Movic (?)") }, + { 0x2F, ("HTR", "E3 Staff (?)") }, + { 0x31, ("VGD", "Vanguard") }, + { 0x32, ("MGT", "Megatron") }, + { 0x33, ("WIZ", "Wiz") }, + { 0x36, ("CAP", "Capcom") }, + }; + + readonly Dictionary saveSizes = new() + { + { SaveTypes.None, 0 }, + { SaveTypes.Sram64Kbit, 1024 * 8 }, + { SaveTypes.Sram256Kbit, 1024 * 32 }, + { SaveTypes.Sram1Mbit, 1024 * 128 }, + { SaveTypes.Sram2Mbit, 1024 * 256 }, + { SaveTypes.Sram4Mbit, 1024 * 512 }, + { SaveTypes.Eeprom1Kbit, 2 * 64 }, + { SaveTypes.Eeprom16Kbit, 2 * 1024 }, + { SaveTypes.Eeprom8Kbit, 2 * 512 }, + }; + + public byte PublisherId { get; private set; } + public SystemTypes SystemType { get; private set; } + public byte GameId { get; private set; } + public byte GameRevision { get; private set; } + public RomSizes RomSize { get; private set; } + public SaveTypes SaveType { get; private set; } + public byte MiscFlags { get; private set; } + public byte RtcPresentFlag { get; private set; } + public ushort Checksum { get; private set; } + + public string PublisherCode => publishers.ContainsKey(PublisherId) ? publishers[PublisherId].code : "???"; + public string PublisherName => publishers.ContainsKey(PublisherId) ? publishers[PublisherId].name : "(Unknown)"; + + public string GameIdString => $"SWJ-{PublisherCode}{(SystemType == SystemTypes.WonderSwan ? "0" : "C")}{GameId:X2}"; + + public Orientations Orientation => (Orientations)(MiscFlags & (1 << 0)); + public RomBusWidths RomBusWidth => (RomBusWidths)(MiscFlags & (1 << 1)); + public RomAccessSpeeds RomAccessSpeed => (RomAccessSpeeds)(MiscFlags & (1 << 2)); + + public int SaveSize => saveSizes.ContainsKey(SaveType) ? saveSizes[SaveType] : 0; + + public bool IsSramSave => + SaveType == SaveTypes.Sram64Kbit || SaveType == SaveTypes.Sram256Kbit || + SaveType == SaveTypes.Sram1Mbit || SaveType == SaveTypes.Sram2Mbit || SaveType == SaveTypes.Sram4Mbit; + + public bool IsEepromSave => + SaveType == SaveTypes.Eeprom1Kbit || SaveType == SaveTypes.Eeprom16Kbit || SaveType == SaveTypes.Eeprom8Kbit; + + public bool IsRtcPresent => RtcPresentFlag != 0; + + public ushort CalculatedChecksum { get; private set; } + + public bool IsChecksumValid => Checksum == CalculatedChecksum; + + public Metadata(byte[] data) + { + var offset = data.Length - 10; + PublisherId = data[offset + 0]; + SystemType = (SystemTypes)data[offset + 1]; + GameId = data[offset + 2]; + GameRevision = data[offset + 3]; + RomSize = (RomSizes)data[offset + 4]; + SaveType = (SaveTypes)data[offset + 5]; + MiscFlags = data[offset + 6]; + RtcPresentFlag = data[offset + 7]; + Checksum = (ushort)(data[offset + 9] << 8 | data[offset + 8]); + + CalculatedChecksum = 0; + for (var i = 0; i < data.Length - 2; i++) + CalculatedChecksum += data[i + 0]; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs.meta new file mode 100644 index 0000000..718ec51 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/Metadata.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6ca048ba38a22c849a012278fc9515f3 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs new file mode 100644 index 0000000..3683a9a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs @@ -0,0 +1,349 @@ +using System; + +using StoicGoose.Common.Utilities; +using StoicGoose.Core.Interfaces; +using StoicGoose.Core.Machines; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Cartridges +{ + /* Seiko S-3511A real-time clock, through Bandai 2003 mapper + * - https://forums.nesdev.org/viewtopic.php?t=21513 + * - https://datasheetspdf.com/pdf-file/1087347/Seiko/S-3511A/1 + */ + + // TODO: interrupts, save/load current state + + public sealed class RTC : IPortAccessComponent + { + const int cyclesInSecond = (int)MachineCommon.CpuClock; + + readonly byte[] numPayloadBytes = new byte[] { 0, 1, 7, 3, 2, 2, 2 }; + readonly int[] numDaysPerMonth = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + /* WS - Status & data registers */ + byte wsData; + byte payloadIndex; + + /* WS+RTC - Communication */ + byte command; + bool isReadAccess; + + /* RTC - Real-time data register */ + byte year, month, day, dayOfWeek, hour, minute, second; + bool isPm, isTestModeActive; + + /* RTC - Status register */ + bool isPowered, is24HourMode; + bool intAE, intME, intFE; + + /* RTC - Alarm time/frequency duty setting register */ + ushort intRegister; + + (bool pm, byte hour, byte minute) alarmTime => (IsBitSet((byte)(intRegister >> 0), 7), (byte)((intRegister >> 0) & 0b00111111), (byte)((intRegister >> 8) & 0b01111111)); + int selectedInterruptFreq + { + get + { + var freq = 0; + for (var j = 0; j < 16; j++) if (((intRegister >> j) & 0b1) == 0b1) freq |= 32768 >> j; + return freq; + } + } + + int cycleCount; + + public RTC() + { + // + } + + public void Reset() + { + wsData = 0; + payloadIndex = 0; + + command = 0; + isReadAccess = false; + + year = dayOfWeek = hour = minute = second = 0; + month = day = 1; + isPm = isTestModeActive = false; + + is24HourMode = intAE = intME = false; + isPowered = intFE = true; + + intRegister = 0x8000; + + cycleCount = 0; + } + + public void Shutdown() + { + // + } + + public void Program(DateTime dateTime) + { + year = (byte)(dateTime.Year % 100); + month = (byte)(dateTime.Month % 13); + day = (byte)(dateTime.Day % 32); + dayOfWeek = (byte)((int)dateTime.DayOfWeek % 8); + hour = (byte)(dateTime.Hour % 25); + minute = (byte)(dateTime.Minute % 60); + second = (byte)(dateTime.Second % 60); + } + + public bool Step(int clockCyclesInStep) + { + var interrupt = false; + + for (var i = 0; i < clockCyclesInStep; i++) + { + if (intFE && !intME) + { + /* Selected frequency steady interrupt output */ + + // TODO probably not right + if (cycleCount >= selectedInterruptFreq) + interrupt = true; + + } + else if (!intFE && intME) + { + /* Per-minute edge interrupt output */ + // TODO + } + else if (intFE && intME) + { + /* Per-minute steady interrupt output */ + // TODO + } + else if (!intFE && !intME && intAE) + { + /* Alarm interrupt output */ + if (alarmTime.pm == isPm && Bcd.BcdToDecimal(alarmTime.hour) == hour && Bcd.BcdToDecimal(alarmTime.minute) == minute) + interrupt = true; + } + + cycleCount++; + if (cycleCount >= cyclesInSecond) + { + UpdateClock(); + cycleCount = 0; + } + } + + return interrupt; + } + + private void UpdateClock() + { + second++; + if (second < 60) return; + + second = 0; + minute++; + if (minute < 60) return; + + minute = 0; + hour++; + if (hour < 24) return; + + hour = 0; + dayOfWeek++; + dayOfWeek %= 7; + + day++; + var extraDay = (month == 2 && (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0)) ? 1 : 0; + if (day < numDaysPerMonth[month] + extraDay) return; + + day = 0; + month++; + if (month < 12) return; + + month = 0; + year++; + } + + private void PerformAccess() + { + switch (command & 0b111) + { + case 0b000: + /* Reset */ + wsData = 0; + + year = 0; + month = 1; + day = 1; + dayOfWeek = 0; + hour = 0; + minute = 0; + second = 0; + + isPowered = is24HourMode = false; + intAE = intME = intFE = false; + + intRegister = 0x0000; + break; + + case 0b001: + /* Status register access */ + if (isReadAccess) + { + wsData = 0; + ChangeBit(ref wsData, 7, isPowered); + ChangeBit(ref wsData, 6, is24HourMode); + ChangeBit(ref wsData, 5, intAE); + ChangeBit(ref wsData, 3, intME); + ChangeBit(ref wsData, 1, intFE); + } + else + { + is24HourMode = IsBitSet(wsData, 6); + intAE = IsBitSet(wsData, 5); + intME = IsBitSet(wsData, 3); + intFE = IsBitSet(wsData, 1); + } + break; + + case 0b010: + /* Real-time data access 1 */ + if (isReadAccess) + { + wsData = 0; + switch (payloadIndex) + { + case 0: wsData = (byte)Bcd.DecimalToBcd(year); break; + case 1: wsData = (byte)Bcd.DecimalToBcd(month); break; + case 2: wsData = (byte)Bcd.DecimalToBcd(day); break; + case 3: wsData = (byte)Bcd.DecimalToBcd(dayOfWeek); break; + case 4: wsData = (byte)Bcd.DecimalToBcd(hour); ChangeBit(ref wsData, 7, isPm); break; + case 5: wsData = (byte)Bcd.DecimalToBcd(minute); break; + case 6: wsData = (byte)Bcd.DecimalToBcd(second); ChangeBit(ref wsData, 7, isTestModeActive); break; + } + } + else + { + switch (payloadIndex) + { + case 0: year = (byte)Bcd.BcdToDecimal(wsData); break; + case 1: month = (byte)Bcd.BcdToDecimal(wsData); break; + case 2: day = (byte)Bcd.BcdToDecimal(wsData); break; + case 3: dayOfWeek = (byte)Bcd.BcdToDecimal(wsData); break; + case 4: hour = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isPm = IsBitSet(wsData, 7); break; + case 5: minute = (byte)Bcd.BcdToDecimal(wsData); break; + case 6: second = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isTestModeActive = IsBitSet(wsData, 7); break; + } + } + break; + + case 0b011: + /* Real-time data access 2 */ + if (isReadAccess) + { + wsData = 0; + switch (payloadIndex) + { + case 0: wsData = (byte)Bcd.DecimalToBcd(hour); ChangeBit(ref wsData, 7, isPm); break; + case 1: wsData = (byte)Bcd.DecimalToBcd(minute); break; + case 2: wsData = (byte)Bcd.DecimalToBcd(second); ChangeBit(ref wsData, 7, isTestModeActive); break; + } + } + else + { + switch (payloadIndex) + { + case 0: hour = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isPm = IsBitSet(wsData, 7); break; + case 1: minute = (byte)Bcd.BcdToDecimal(wsData); break; + case 2: second = (byte)(Bcd.BcdToDecimal(wsData) & 0b01111111); isTestModeActive = IsBitSet(wsData, 7); break; + } + } + break; + + case 0b100: + /* Alarm time/frequency duty setting */ + if (isReadAccess) + { + wsData = 0; + switch (payloadIndex) + { + case 0: wsData = (byte)((intRegister >> 0) & 0xFF); break; + case 1: wsData = (byte)((intRegister >> 8) & 0xFF); break; + } + } + else + { + switch (payloadIndex) + { + case 0: intRegister = (ushort)((intRegister & 0xFF00) | (wsData << 0)); break; + case 1: intRegister = (ushort)((intRegister & 0x00FF) | (wsData << 8)); break; + } + } + break; + + case 0b101: + /* Unknown/invalid */ + if (isReadAccess) + { + wsData = 0xFF; + } + break; + + case 0b110: + /* Test mode start -- ignored */ + break; + + case 0b111: + /* Test mode end -- ignored */ + break; + + default: + break; + } + } + + public byte ReadPort(ushort port) + { + var retVal = (byte)0x90; + + if (port == 0) + { + PerformAccess(); + + payloadIndex++; + + ChangeBit(ref retVal, 7, true); // TODO: correct? + ChangeBit(ref retVal, 4, payloadIndex < numPayloadBytes[command & 0b111]); + ChangeBit(ref retVal, 0, true); + retVal |= (byte)((command & 0b1111) << 1); + + if (payloadIndex >= numPayloadBytes[command & 0b111]) + payloadIndex = 0; + } + else if (port == 1) + { + retVal = wsData; + } + + return retVal; + } + + public void WritePort(ushort port, byte value) + { + if (port == 0) + { + isReadAccess = IsBitSet(value, 0); + command = (byte)((value >> 1) & 0b111); + + PerformAccess(); + } + else if (port == 1) + { + wsData = value; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs.meta new file mode 100644 index 0000000..e6e61b3 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Cartridges/RTC.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: acdef41e0d8804e45a3033ad3f95f77e \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA.meta new file mode 100644 index 0000000..223301e --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e29bbdbdcb911604ea0efb453913bff8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs new file mode 100644 index 0000000..33e2f3f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs @@ -0,0 +1,168 @@ +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.DMA +{ + public class SphinxGeneralDMAController : IPortAccessComponent + { + // TODO: verify behavior! + + readonly IMachine machine = default; + + /* REG_DMA_SRC(_HI) */ + uint dmaSource; + /* REG_DMA_DST */ + ushort dmaDestination; + /* REG_DMA_LEN */ + ushort dmaLength; + /* REG_DMA_CTRL */ + byte dmaControl; + + public bool IsActive => IsBitSet(dmaControl, 7); + + bool isDecrementMode => IsBitSet(dmaControl, 6); + + public SphinxGeneralDMAController(IMachine machine) + { + this.machine = machine; + } + + public void Reset() + { + // + + ResetRegisters(); + } + + private void ResetRegisters() + { + dmaSource = dmaDestination = dmaLength = dmaControl = 0; + } + + public void Shutdown() + { + // + } + + public int Step() + { + if (dmaLength == 0 || ((dmaSource >> 16) & 0x0F) == 0x01) + { + /* Disable DMA if length is zero OR source is SRAM */ + ChangeBit(ref dmaControl, 7, false); + return 5; + } + else + { + if (((dmaSource >> 16) & 0x0F) != 0x01) + { + /* Perform DMA if source is not SRAM */ + machine.WriteMemory((uint)(dmaDestination + 0), machine.ReadMemory(dmaSource + 0)); + machine.WriteMemory((uint)(dmaDestination + 1), machine.ReadMemory(dmaSource + 1)); + } + + dmaSource += (uint)(isDecrementMode ? -2 : 2); + dmaDestination += (ushort)(isDecrementMode ? -2 : 2); + dmaLength -= 2; + + return 2; + } + } + + public byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x40: + /* REG_DMA_SRC (low) */ + retVal |= (byte)((dmaSource >> 0) & 0xFE); + break; + case 0x41: + /* REG_DMA_SRC (mid) */ + retVal |= (byte)((dmaSource >> 8) & 0xFF); + break; + case 0x42: + /* REG_DMA_SRC_HI */ + retVal |= (byte)((dmaSource >> 16) & 0x0F); + break; + + case 0x44: + /* REG_DMA_DST (low) */ + retVal |= (byte)((dmaDestination >> 0) & 0xFE); + break; + case 0x45: + /* REG_DMA_DST (high) */ + retVal |= (byte)((dmaDestination >> 8) & 0xFF); + break; + + case 0x46: + /* REG_DMA_LEN */ + retVal |= (byte)((dmaLength >> 0) & 0xFE); + break; + case 0x47: + /* REG_DMA_LEN */ + retVal |= (byte)((dmaLength >> 8) & 0xFF); + break; + + case 0x48: + /* REG_DMA_CTRL */ + retVal |= (byte)(dmaControl & 0b11000000); + break; + } + + return retVal; + } + + public void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x40: + /* REG_DMA_SRC (low) */ + dmaSource &= 0xFFF00; + dmaSource |= (uint)((value << 0) & 0x000FE); + break; + case 0x41: + /* REG_DMA_SRC (high) */ + dmaSource &= 0xF00FE; + dmaSource |= (uint)((value << 8) & 0x0FF00); + break; + case 0x42: + /* REG_DMA_SRC_HI */ + dmaSource &= 0x0FFFE; + dmaSource |= (uint)((value << 16) & 0xF0000); + break; + + case 0x44: + /* REG_DMA_DST (low) */ + dmaDestination &= 0xFF00; + dmaDestination |= (ushort)((value << 0) & 0x00FE); + break; + case 0x45: + /* REG_DMA_DST (high) */ + dmaDestination &= 0x00FE; + dmaDestination |= (ushort)((value << 8) & 0xFF00); + break; + + case 0x46: + /* REG_DMA_LEN (low) */ + dmaLength &= 0xFF00; + dmaLength |= (ushort)((value << 0) & 0x00FE); + break; + case 0x47: + /* REG_DMA_LEN (high) */ + dmaLength &= 0x00FE; + dmaLength |= (ushort)((value << 8) & 0xFF00); + break; + + case 0x48: + /* REG_DMA_CTRL */ + dmaControl = (byte)(value & 0b11000000); + break; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs.meta new file mode 100644 index 0000000..12b199a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxGeneralDMAController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8e43c53f0ef2ab24e9aec07a2ca82f6b \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs new file mode 100644 index 0000000..9194242 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs @@ -0,0 +1,173 @@ +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.DMA +{ + public class SphinxSoundDMAController : IPortAccessComponent + { + readonly static int[] cycleCounts = { 768, 512, 256, 128 }; + + readonly static ushort destinationPortChannel2Volume = 0x089; + readonly static ushort destinationPortHyperVoice = 0x095; + + readonly IMachine machine = default; + + /* REG_DMA_SRC(_HI) */ + uint dmaSource; + /* REG_DMA_LEN(_HI) */ + uint dmaLength; + /* REG_DMA_CTRL */ + byte dmaControl; + + public bool IsActive => IsBitSet(dmaControl, 7); + + bool isDecrementMode => IsBitSet(dmaControl, 6); + bool isDestinationHyperVoice => IsBitSet(dmaControl, 4); + bool isLoopingMode => IsBitSet(dmaControl, 3); + int dmaRate => dmaControl & 0b11; + + uint initialSource, initialLength; + + int cycleCount; + + public SphinxSoundDMAController(IMachine machine) + { + this.machine = machine; + } + + public void Reset() + { + initialSource = initialLength = 0; + + cycleCount = 0; + + ResetRegisters(); + } + + private void ResetRegisters() + { + dmaSource = dmaLength = dmaControl = 0; + } + + public void Shutdown() + { + // + } + + public void Step(int clockCyclesInStep) + { + cycleCount += clockCyclesInStep; + + if (cycleCount >= cycleCounts[dmaRate]) + { + machine.WritePort(isDestinationHyperVoice ? destinationPortHyperVoice : destinationPortChannel2Volume, machine.ReadMemory(dmaSource)); + + dmaSource += (uint)(isDecrementMode ? -1 : 1); + dmaLength--; + + if (dmaLength == 0) + { + if (isLoopingMode) + { + dmaSource = initialSource; + dmaLength = initialLength; + } + else + ChangeBit(ref dmaControl, 7, false); + } + + cycleCount = 0; + } + } + + public byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x4A: + /* REG_SDMA_SRC (low) */ + retVal |= (byte)((dmaSource >> 0) & 0xFF); + break; + case 0x4B: + /* REG_SDMA_SRC (mid) */ + retVal |= (byte)((dmaSource >> 8) & 0xFF); + break; + case 0x4C: + /* REG_SDMA_SRC_HI */ + retVal |= (byte)((dmaSource >> 16) & 0x0F); + break; + + case 0x4E: + /* REG_SDMA_LEN (low) */ + retVal |= (byte)((dmaLength >> 0) & 0xFE); + break; + case 0x4F: + /* REG_SDMA_LEN (mid) */ + retVal |= (byte)((dmaLength >> 8) & 0xFF); + break; + case 0x50: + /* REG_SDMA_LEN_HI */ + retVal |= (byte)((dmaLength >> 16) & 0x0F); + break; + + case 0x52: + /* REG_SDMA_CTRL */ + retVal |= (byte)(dmaControl & 0b11011111); + break; + } + + return retVal; + } + + public void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x4A: + /* REG_SDMA_SRC (low) */ + dmaSource &= 0xFFF00; + dmaSource |= (uint)((value << 0) & 0x000FF); + break; + case 0x4B: + /* REG_SDMA_SRC (mid) */ + dmaSource &= 0xF00FF; + dmaSource |= (uint)((value << 8) & 0x0FF00); + break; + case 0x4C: + /* REG_SDMA_SRC_HI */ + dmaSource &= 0x0FFFF; + dmaSource |= (uint)((value << 16) & 0xF0000); + break; + + case 0x4E: + /* REG_SDMA_LEN (low) */ + dmaLength &= 0xFFF00; + dmaLength |= (ushort)((value << 0) & 0x00FF); + break; + case 0x4F: + /* REG_SDMA_LEN (mid) */ + dmaLength &= 0xF00FF; + dmaLength |= (ushort)((value << 8) & 0xFF00); + break; + case 0x50: + /* REG_SDMA_SRC_HI */ + dmaLength &= 0x0FFFF; + dmaLength |= (uint)((value << 16) & 0xF0000); + break; + + case 0x52: + /* REG_SDMA_CTRL */ + if (!IsActive && IsBitSet(value, 7)) + { + initialSource = dmaSource; + initialLength = dmaLength; + } + dmaControl = (byte)(value & 0b11011111); + break; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs.meta new file mode 100644 index 0000000..3c50aab --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/DMA/SphinxSoundDMAController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ef4ffde1da744e54fb8facfbc5fac13f \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display.meta new file mode 100644 index 0000000..cc2f4be --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3611bec488c079c419db211c75d1afd1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs new file mode 100644 index 0000000..7449805 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs @@ -0,0 +1,179 @@ +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Display +{ + public sealed class AswanDisplayController : DisplayControllerCommon + { + public AswanDisplayController(IMachine machine) : base(machine) { } + + protected override void RenderSleep(int y, int x) + { + DisplayUtilities.CopyPixel((255, 255, 255), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderBackColor(int y, int x) + { + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[backColorIndex & 0b0111])), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderSCR1(int y, int x) + { + if (!scr1Enable) return; + + var scrollX = (x + scr1ScrollX) & 0xFF; + var scrollY = (y + scr1ScrollY) & 0xFF; + + var mapOffset = (uint)((scr1Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1)); + var attribs = ReadMemory16(mapOffset); + var tileNum = (ushort)(attribs & 0x01FF); + var tilePal = (byte)((attribs >> 9) & 0b1111); + + var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), false, false, false); + + var isOpaque = !IsBitSet(tilePal, 2) || pixelColor != 0; + if (!isOpaque) return; + + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderSCR2(int y, int x) + { + if (!scr2Enable) return; + + var scrollX = (x + scr2ScrollX) & 0xFF; + var scrollY = (y + scr2ScrollY) & 0xFF; + + var mapOffset = (uint)((scr2Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1)); + var attribs = ReadMemory16(mapOffset); + var tileNum = (ushort)(attribs & 0x01FF); + var tilePal = (byte)((attribs >> 9) & 0b1111); + + var isVisible = !scr2WindowEnable || (scr2WindowEnable && ((!scr2WindowDisplayOutside && IsInsideSCR2Window(y, x)) || (scr2WindowDisplayOutside && IsOutsideSCR2Window(y, x)))); + if (!isVisible) return; + + var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), false, false, false); + + var isOpaque = !IsBitSet(tilePal, 2) || pixelColor != 0; + if (!isOpaque) return; + + isUsedBySCR2[(y * HorizontalDisp) + x] = true; + + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderSprites(int y, int x) + { + if (!sprEnable) return; + + if (x == 0) + { + activeSpriteCountOnLine = 0; + for (var i = 0; i < spriteCountNextFrame; i++) + { + var spriteY = (spriteData[i] >> 16) & 0xFF; + if ((byte)(y - spriteY) <= 7 && activeSpriteCountOnLine < maxSpritesPerLine) + activeSpritesOnLine[activeSpriteCountOnLine++] = spriteData[i]; + } + } + + for (var i = 0; i < activeSpriteCountOnLine; i++) + { + var activeSprite = activeSpritesOnLine[i]; + + var spriteX = (activeSprite >> 24) & 0xFF; + if (x < 0 || x >= HorizontalDisp || (byte)(x - spriteX) > 7) continue; + + var windowDisplayOutside = ((activeSprite >> 12) & 0b1) == 0b1; + if (!sprWindowEnable || (sprWindowEnable && (windowDisplayOutside != IsInsideSPRWindow(y, x)))) + { + var tileNum = (ushort)(activeSprite & 0x01FF); + var tilePal = (byte)((activeSprite >> 9) & 0b111); + var priorityAboveSCR2 = ((activeSprite >> 13) & 0b1) == 0b1; + var spriteY = (activeSprite >> 16) & 0xFF; + + var isVisible = !isUsedBySCR2[(y * HorizontalDisp) + x] || priorityAboveSCR2; + if (!isVisible) continue; + + var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, (byte)((y - spriteY) ^ (((activeSprite >> 15) & 0b1) * 7)), (byte)((x - spriteX) ^ (((activeSprite >> 14) & 0b1) * 7)), false, false, false); + + var isOpaque = !IsBitSet(tilePal, 2) || pixelColor != 0; + if (!isOpaque) continue; + + tilePal += 8; + + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp); + } + } + } + + public override byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x01: + /* REG_BACK_COLOR */ + retVal |= (byte)(backColorIndex & 0b111); + break; + + case 0x04: + /* REG_SPR_BASE */ + retVal |= (byte)(sprBase & 0b11111); + break; + + case 0x07: + /* REG_MAP_BASE */ + retVal |= (byte)((scr1Base & 0b111) << 0); + retVal |= (byte)((scr2Base & 0b111) << 4); + break; + + case 0x14: + /* REG_LCD_CTRL */ + ChangeBit(ref retVal, 0, lcdActive); + break; + + default: + /* Fall through to common */ + retVal = base.ReadPort(port); + break; + } + + return retVal; + } + + public override void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x01: + /* REG_BACK_COLOR */ + backColorIndex = (byte)(value & 0b111); + break; + + case 0x04: + /* REG_SPR_BASE */ + sprBase = (byte)(value & 0b11111); + break; + + case 0x07: + /* REG_MAP_BASE */ + scr1Base = (byte)((value >> 0) & 0b111); + scr2Base = (byte)((value >> 4) & 0b111); + break; + + case 0x14: + /* REG_LCD_CTRL */ + lcdActive = IsBitSet(value, 0); + break; + + default: + /* Fall through to common */ + base.WritePort(port, value); + break; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs.meta new file mode 100644 index 0000000..ce2209d --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/AswanDisplayController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7245d0f687e243a4d9389a2c3c37d708 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs new file mode 100644 index 0000000..be60c60 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs @@ -0,0 +1,743 @@ +using System; + +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Interfaces; +using StoicGoose.Core.Machines; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Display +{ + public abstract class DisplayControllerCommon : IPortAccessComponent + { + public const int HorizontalDisp = 224; + public const int HorizontalBlank = 32; + public const int HorizontalTotal = HorizontalDisp + HorizontalBlank; + public const double HorizontalClock = MachineCommon.CpuClock / HorizontalTotal; + + public const int VerticalDisp = 144; + public const int VerticalBlank = 15; + public const int VerticalTotal = VerticalDisp + VerticalBlank; + public const double VerticalClock = 12000.0 / VerticalTotal; + + public const int ScreenWidth = HorizontalDisp; + public const int ScreenHeight = VerticalDisp; + + protected const int maxSpriteCount = 128; + protected const int maxSpritesPerLine = 32; + + [Flags] + public enum DisplayInterrupts + { + None = 0, + LineCompare = 1 << 0, + VBlankTimer = 1 << 1, + VBlank = 1 << 2, + HBlankTimer = 1 << 3 + } + + protected readonly uint[] spriteData = new uint[maxSpriteCount]; + protected readonly uint[] spriteDataNextFrame = new uint[maxSpriteCount]; + protected readonly uint[] activeSpritesOnLine = new uint[maxSpritesPerLine]; + + protected readonly bool[] isUsedBySCR2 = new bool[HorizontalDisp * VerticalDisp]; + + protected int spriteCountNextFrame = 0, activeSpriteCountOnLine = 0; + + protected int cycleCount = 0; + protected readonly byte[] outputFramebuffer = new byte[ScreenWidth * ScreenHeight * 4]; + + public Action SendFramebuffer { get; set; } = default; + + protected readonly IMachine machine = default; + + /* REG_DISP_CTRL */ + protected bool scr1Enable, scr2Enable, sprEnable, sprWindowEnable, scr2WindowDisplayOutside, scr2WindowEnable; + /* REG_BACK_COLOR */ + protected byte backColorIndex; + /* REG_LINE_xxx */ + protected int lineCurrent, lineCompare; + /* REG_SPR_xxx */ + protected int sprBase, sprFirst, sprCount; + /* REG_MAP_BASE */ + protected int scr1Base, scr2Base; + /* REG_SCR2_WIN_xx */ + protected int scr2WinX0, scr2WinY0, scr2WinX1, scr2WinY1; + /* REG_SPR_WIN_xx */ + protected int sprWinX0, sprWinY0, sprWinX1, sprWinY1; + /* REG_SCR1_xx */ + protected int scr1ScrollX, scr1ScrollY; + /* REG_SCR2_xx */ + protected int scr2ScrollX, scr2ScrollY; + /* REG_LCD_xxx */ + protected bool lcdActive; + protected bool iconSleep, iconVertical, iconHorizontal, iconAux1, iconAux2, iconAux3; + protected int vtotal, vsync; + /* REG_PALMONO_POOL_x */ + protected readonly byte[] palMonoPools = default; + /* REG_PALMONO_x */ + protected readonly byte[][] palMonoData = default; + /* REG_xTMR_xxx */ + protected readonly DisplayTimer hBlankTimer = new(), vBlankTimer = new(); + + public DisplayControllerCommon(IMachine machine) + { + this.machine = machine; + + palMonoPools = new byte[8]; + palMonoData = new byte[16][]; + for (var i = 0; i < palMonoData.GetLength(0); i++) palMonoData[i] = new byte[4]; + } + + public void Reset() + { + cycleCount = 0; + + Array.Fill(outputFramebuffer, 255); + + Array.Fill(isUsedBySCR2, false); + + Array.Fill(spriteData, 0); + Array.Fill(spriteDataNextFrame, 0); + Array.Fill(activeSpritesOnLine, 0); + + spriteCountNextFrame = 0; + activeSpriteCountOnLine = 0; + + ResetRegisters(); + } + + protected virtual void ResetRegisters() + { + scr1Enable = scr2Enable = sprEnable = sprWindowEnable = scr2WindowDisplayOutside = scr2WindowEnable = false; + backColorIndex = 0; + lineCurrent = lineCompare = 0; + sprBase = sprFirst = sprCount = 0; + scr1Base = scr2Base = 0; + scr2WinX0 = scr2WinY0 = scr2WinX1 = scr2WinY1 = 0; + sprWinX0 = sprWinY0 = sprWinX1 = sprWinY1 = 0; + scr1ScrollX = scr1ScrollY = 0; + scr2ScrollX = scr2ScrollY = 0; + lcdActive = true; /* NOTE: Final Lap 2000 depends on bootstrap doing this, otherwise LCD stays off? */ + iconSleep = iconVertical = iconHorizontal = iconAux1 = iconAux2 = iconAux3 = false; + vtotal = VerticalTotal - 1; + vsync = VerticalTotal - 4; /* NOTE: Full usage/meaning unknown, so we're ignoring it for now */ + Array.Fill(palMonoPools, 0); + for (var i = 0; i < palMonoData.GetLength(0); i++) Array.Fill(palMonoData[i], 0); + hBlankTimer.Reset(); + vBlankTimer.Reset(); + } + + public void Shutdown() + { + /* Nothing to do... */ + } + + public DisplayInterrupts Step(int clockCyclesInStep) + { + var interrupt = DisplayInterrupts.None; + + cycleCount += clockCyclesInStep; + + if (cycleCount >= HorizontalTotal) + { + /* Sprite fetch */ + if (lineCurrent == VerticalDisp - 2) + { + spriteCountNextFrame = 0; + for (var j = sprFirst; j < sprFirst + Math.Min(maxSpriteCount, sprCount); j++) + { + var k = (uint)((sprBase << 9) + (j << 2)); + spriteDataNextFrame[spriteCountNextFrame++] = (uint)(machine.ReadMemory(k + 3) << 24 | machine.ReadMemory(k + 2) << 16 | machine.ReadMemory(k + 1) << 8 | machine.ReadMemory(k + 0)); + } + } + + /* Render pixels */ + for (var x = 0; x < HorizontalDisp; x++) + RenderPixel(lineCurrent, x); + + /* Line compare interrupt */ + if (lineCurrent == lineCompare) + interrupt |= DisplayInterrupts.LineCompare; + + /* H-timer interrupt */ + if (hBlankTimer.Step()) + interrupt |= DisplayInterrupts.HBlankTimer; + + /* V-blank interrupt */ + if (lineCurrent == VerticalDisp) + { + interrupt |= DisplayInterrupts.VBlank; + + /* V-timer interrupt */ + if (vBlankTimer.Step()) + interrupt |= DisplayInterrupts.VBlankTimer; + + /* Transfer framebuffer */ + SendFramebuffer?.Invoke(outputFramebuffer.Clone() as byte[]); + } + + /* Advance scanline */ + lineCurrent++; + + /* Is frame finished? */ + if (lineCurrent > Math.Max(VerticalDisp, vtotal)) + { + /* Copy sprite data for next frame */ + for (int j = 0, k = spriteCountNextFrame - 1; k >= 0; j++, k--) spriteData[j] = spriteDataNextFrame[k]; + Array.Fill(spriteDataNextFrame, 0); + + /* Reset variables */ + lineCurrent = 0; + Array.Fill(isUsedBySCR2, false); + } + + /* End of scanline */ + cycleCount = 0; + } + + return interrupt; + } + + protected void RenderPixel(int y, int x) + { + if (y < 0 || y >= VerticalDisp || x < 0 || x >= HorizontalDisp) return; + + if (lcdActive) + { + RenderBackColor(y, x); + RenderSCR1(y, x); + RenderSCR2(y, x); + RenderSprites(y, x); + } + else + { + /* LCD sleeping */ + RenderSleep(y, x); + } + } + + protected abstract void RenderSleep(int y, int x); + protected abstract void RenderBackColor(int y, int x); + protected abstract void RenderSCR1(int y, int x); + protected abstract void RenderSCR2(int y, int x); + protected abstract void RenderSprites(int y, int x); + + protected static void ValidateWindowCoordinates(ref int x0, ref int x1, ref int y0, ref int y1) + { + /* Thank you for this fix, for the encouragement and hints and advice, for just having been there... Thank you for everything, Near. + * https://forum.fobby.net/index.php?t=msg&goto=6085 */ + + if (x0 > x1) + (x1, x0) = (x0, x1); + + if (y0 > y1) + (y1, y0) = (y0, y1); + } + + protected bool IsInsideSCR2Window(int y, int x) + { + var x0 = scr2WinX0; + var x1 = scr2WinX1; + var y0 = scr2WinY0; + var y1 = scr2WinY1; + + ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); + + return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) && + ((y >= y0 && y <= y1) || (y >= y1 && y <= y0)); + } + + protected bool IsOutsideSCR2Window(int y, int x) + { + var x0 = scr2WinX0; + var x1 = scr2WinX1; + var y0 = scr2WinY0; + var y1 = scr2WinY1; + + ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); + + return x < x0 || x > x1 || y < y0 || y > y1; + } + + protected bool IsInsideSPRWindow(int y, int x) + { + var x0 = sprWinX0; + var x1 = sprWinX1; + var y0 = sprWinY0; + var y1 = sprWinY1; + + ValidateWindowCoordinates(ref x0, ref x1, ref y0, ref y1); + + return ((x >= x0 && x <= x1) || (x >= x1 && x <= x0)) && + ((y >= y0 && y <= y1) || (y >= y1 && y <= y0)); + } + + protected byte ReadMemory8(uint address) => machine.ReadMemory(address); + protected ushort ReadMemory16(uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + protected uint ReadMemory32(uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + + public virtual byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x00: + /* REG_DISP_CTRL */ + ChangeBit(ref retVal, 0, scr1Enable); + ChangeBit(ref retVal, 1, scr2Enable); + ChangeBit(ref retVal, 2, sprEnable); + ChangeBit(ref retVal, 3, sprWindowEnable); + ChangeBit(ref retVal, 4, scr2WindowDisplayOutside); + ChangeBit(ref retVal, 5, scr2WindowEnable); + break; + + case 0x02: + /* REG_LINE_CUR */ + retVal |= (byte)(lineCurrent & 0xFF); + break; + + case 0x03: + /* REG_LINE_CMP */ + retVal |= (byte)(lineCompare & 0xFF); + break; + + case 0x05: + /* REG_SPR_FIRST */ + retVal |= (byte)(sprFirst & 0x7F); + break; + + case 0x06: + /* REG_SPR_COUNT */ + retVal |= (byte)(sprCount & 0xFF); + break; + + case 0x08: + /* REG_SCR2_WIN_X0 */ + retVal |= (byte)(scr2WinX0 & 0xFF); + break; + + case 0x09: + /* REG_SCR2_WIN_Y0 */ + retVal |= (byte)(scr2WinY0 & 0xFF); + break; + + case 0x0A: + /* REG_SCR2_WIN_X1 */ + retVal |= (byte)(scr2WinX1 & 0xFF); + break; + + case 0x0B: + /* REG_SCR2_WIN_Y1 */ + retVal |= (byte)(scr2WinY1 & 0xFF); + break; + + case 0x0C: + /* REG_SPR_WIN_X0 */ + retVal |= (byte)(sprWinX0 & 0xFF); + break; + + case 0x0D: + /* REG_SPR_WIN_Y0 */ + retVal |= (byte)(sprWinY0 & 0xFF); + break; + + case 0x0E: + /* REG_SPR_WIN_X1 */ + retVal |= (byte)(sprWinX1 & 0xFF); + break; + + case 0x0F: + /* REG_SPR_WIN_Y1 */ + retVal |= (byte)(sprWinY1 & 0xFF); + break; + + case 0x10: + /* REG_SCR1_X */ + retVal |= (byte)(scr1ScrollX & 0xFF); + break; + + case 0x11: + /* REG_SCR1_Y */ + retVal |= (byte)(scr1ScrollY & 0xFF); + break; + + case 0x12: + /* REG_SCR2_X */ + retVal |= (byte)(scr2ScrollX & 0xFF); + break; + + case 0x13: + /* REG_SCR2_Y */ + retVal |= (byte)(scr2ScrollY & 0xFF); + break; + + case 0x15: + /* REG_LCD_ICON */ + ChangeBit(ref retVal, 0, iconSleep); + ChangeBit(ref retVal, 1, iconVertical); + ChangeBit(ref retVal, 2, iconHorizontal); + ChangeBit(ref retVal, 3, iconAux1); + ChangeBit(ref retVal, 4, iconAux2); + ChangeBit(ref retVal, 5, iconAux3); + break; + + case 0x16: + /* REG_LCD_VTOTAL */ + retVal |= (byte)(vtotal & 0xFF); + break; + + case 0x17: + /* REG_LCD_VSYNC */ + retVal |= (byte)(vsync & 0xFF); + break; + + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + /* REG_PALMONO_POOL_x */ + retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 0] << 0); + retVal |= (byte)(palMonoPools[((port & 0b11) << 1) | 1] << 4); + break; + + case ushort _ when port >= 0x20 && port <= 0x3F: + /* REG_PALMONO_x */ + retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] << 0); + retVal |= (byte)(palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] << 4); + break; + + case 0xA2: + /* REG_TMR_CTRL */ + ChangeBit(ref retVal, 0, hBlankTimer.Enable); + ChangeBit(ref retVal, 1, hBlankTimer.Repeating); + ChangeBit(ref retVal, 2, vBlankTimer.Enable); + ChangeBit(ref retVal, 3, vBlankTimer.Repeating); + break; + + case 0xA4: + case 0xA5: + /* REG_HTMR_FREQ */ + retVal |= (byte)((hBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0xA6: + case 0xA7: + /* REG_VTMR_FREQ */ + retVal |= (byte)((vBlankTimer.Frequency >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0xA8: + case 0xA9: + /* REG_HTMR_CTR */ + retVal |= (byte)((hBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0xAA: + case 0xAB: + /* REG_VTMR_CTR */ + retVal |= (byte)((vBlankTimer.Counter >> ((port & 0b1) * 8)) & 0xFF); + break; + } + + return retVal; + } + + public virtual void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x00: + /* REG_DISP_CTRL */ + scr1Enable = IsBitSet(value, 0); + scr2Enable = IsBitSet(value, 1); + sprEnable = IsBitSet(value, 2); + sprWindowEnable = IsBitSet(value, 3); + scr2WindowDisplayOutside = IsBitSet(value, 4); + scr2WindowEnable = IsBitSet(value, 5); + break; + + case 0x03: + /* REG_LINE_CMP */ + lineCompare = (byte)(value & 0xFF); + break; + + case 0x05: + /* REG_SPR_FIRST */ + sprFirst = (byte)(value & 0x7F); + break; + + case 0x06: + /* REG_SPR_COUNT */ + sprCount = (byte)(value & 0xFF); + break; + + case 0x08: + /* REG_SCR2_WIN_X0 */ + scr2WinX0 = (byte)(value & 0xFF); + break; + + case 0x09: + /* REG_SCR2_WIN_Y0 */ + scr2WinY0 = (byte)(value & 0xFF); + break; + + case 0x0A: + /* REG_SCR2_WIN_X1 */ + scr2WinX1 = (byte)(value & 0xFF); + break; + + case 0x0B: + /* REG_SCR2_WIN_Y1 */ + scr2WinY1 = (byte)(value & 0xFF); + break; + + case 0x0C: + /* REG_SPR_WIN_X0 */ + sprWinX0 = (byte)(value & 0xFF); + break; + + case 0x0D: + /* REG_SPR_WIN_Y0 */ + sprWinY0 = (byte)(value & 0xFF); + break; + + case 0x0E: + /* REG_SPR_WIN_X1 */ + sprWinX1 = (byte)(value & 0xFF); + break; + + case 0x0F: + /* REG_SPR_WIN_Y1 */ + sprWinY1 = (byte)(value & 0xFF); + break; + + case 0x10: + /* REG_SCR1_X */ + scr1ScrollX = (byte)(value & 0xFF); + break; + + case 0x11: + /* REG_SCR1_Y */ + scr1ScrollY = (byte)(value & 0xFF); + break; + + case 0x12: + /* REG_SCR2_X */ + scr2ScrollX = (byte)(value & 0xFF); + break; + + case 0x13: + /* REG_SCR2_Y */ + scr2ScrollY = (byte)(value & 0xFF); + break; + + case 0x15: + /* REG_LCD_ICON */ + iconSleep = IsBitSet(value, 0); + iconVertical = IsBitSet(value, 1); + iconHorizontal = IsBitSet(value, 2); + iconAux1 = IsBitSet(value, 3); + iconAux2 = IsBitSet(value, 4); + iconAux3 = IsBitSet(value, 5); + break; + + case 0x16: + /* REG_LCD_VTOTAL */ + vtotal = (byte)(value & 0xFF); + break; + + case 0x17: + /* REG_LCD_VSYNC */ + vsync = (byte)(value & 0xFF); + break; + + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + /* REG_PALMONO_POOL_x */ + palMonoPools[((port & 0b11) << 1) | 0] = (byte)((value >> 0) & 0b1111); + palMonoPools[((port & 0b11) << 1) | 1] = (byte)((value >> 4) & 0b1111); + break; + + case ushort _ when port >= 0x20 && port <= 0x3F: + /* REG_PALMONO_x */ + palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 0] = (byte)((value >> 0) & 0b111); + palMonoData[(port >> 1) & 0b1111][((port & 0b1) << 1) | 1] = (byte)((value >> 4) & 0b111); + break; + + case 0xA2: + /* REG_TMR_CTRL */ + hBlankTimer.Enable = IsBitSet(value, 0); + hBlankTimer.Repeating = IsBitSet(value, 1); + vBlankTimer.Enable = IsBitSet(value, 2); + vBlankTimer.Repeating = IsBitSet(value, 3); + break; + + case 0xA4: + /* REG_HTMR_FREQ (low) */ + hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0xFF00) | value); + hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0xFF00) | value); + break; + + case 0xA5: + /* REG_HTMR_FREQ (high) */ + hBlankTimer.Frequency = (ushort)((hBlankTimer.Frequency & 0x00FF) | (value << 8)); + hBlankTimer.Counter = (ushort)((hBlankTimer.Counter & 0x00FF) | (value << 8)); + break; + + case 0xA6: + /* REG_VTMR_FREQ (low) */ + vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0xFF00) | value); + vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0xFF00) | value); + break; + + case 0xA7: + /* REG_VTMR_FREQ (high) */ + vBlankTimer.Frequency = (ushort)((vBlankTimer.Frequency & 0x00FF) | (value << 8)); + vBlankTimer.Counter = (ushort)((vBlankTimer.Counter & 0x00FF) | (value << 8)); + break; + } + } + + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR1 enable", 0)] + public bool Scr1Enable => scr1Enable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR2 enable", 1)] + public bool Scr2Enable => scr2Enable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SPR enable", 2)] + public bool SprEnable => sprEnable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SPR window enable", 3)] + public bool SprWindowEnable => sprWindowEnable; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR2 window mode; display outside?", 4)] + public bool Scr2WindowDisplayOutside => scr2WindowDisplayOutside; + [Port("REG_DISP_CTRL", 0x000)] + [BitDescription("SCR2 window enable", 5)] + public bool Scr2WindowEnable => scr2WindowEnable; + [Port("REG_BACK_COLOR", 0x001)] + [BitDescription("Background color pool index", 0, 2)] + public virtual byte BackColorIndex => backColorIndex; + [Port("REG_LINE_CUR", 0x002)] + [BitDescription("Current line being drawn")] + public int LineCurrent => lineCurrent; + [Port("REG_LINE_CMP", 0x003)] + [BitDescription("Line compare interrupt line")] + public int LineCompare => lineCompare; + [Port("REG_SPR_BASE", 0x004)] + [BitDescription("Sprite table base address", 0, 4)] + [Format("X4", 9)] + public virtual int SprBase => sprBase; + [Port("REG_SPR_FIRST", 0x005)] + [BitDescription("First sprite to draw", 0, 6)] + public int SprFirst => sprFirst; + [Port("REG_SPR_COUNT", 0x006)] + [BitDescription("Number of sprites to draw")] + public int SprCount => sprCount; + [Port("REG_MAP_BASE", 0x007)] + [BitDescription("SCR1 base address", 0, 2)] + [Format("X4", 11)] + public virtual int Scr1Base => scr1Base; + [Port("REG_MAP_BASE", 0x007)] + [BitDescription("SCR2 base address", 4, 6)] + [Format("X4", 11)] + public virtual int Scr2Base => scr2Base; + [Port("REG_SCR2_WIN_X0", 0x008)] + [BitDescription("Top-left X of SCR2 window")] + public int Scr2WinX0 => scr2WinX0; + [Port("REG_SCR2_WIN_Y0", 0x009)] + [BitDescription("Top-left Y of SCR2 window")] + public int Scr2WinY0 => scr2WinY0; + [Port("REG_SCR2_WIN_X1", 0x00A)] + [BitDescription("Bottom-right X of SCR2 window")] + public int Scr2WinX1 => scr2WinX1; + [Port("REG_SCR2_WIN_Y1", 0x00B)] + [BitDescription("Bottom-right Y of SCR2 window")] + public int Scr2WinY1 => scr2WinY1; + [Port("REG_SPR_WIN_X0", 0x00C)] + [BitDescription("Top-left X of SPR window")] + public int SprWinX0 => sprWinX0; + [Port("REG_SPR_WIN_Y0", 0x00D)] + [BitDescription("Top-left Y of SPR window")] + public int SprWinY0 => sprWinY0; + [Port("REG_SPR_WIN_X1", 0x00E)] + [BitDescription("Bottom-right X of SPR window")] + public int SprWinX1 => sprWinX1; + [Port("REG_SPR_WIN_Y1", 0x00F)] + [BitDescription("Bottom-right Y of SPR window")] + public int SprWinY1 => sprWinY1; + [Port("REG_SCR1_X", 0x010)] + [BitDescription("SCR1 X scroll")] + public int Scr1ScrollX => scr1ScrollX; + [Port("REG_SCR1_Y", 0x011)] + [BitDescription("SCR1 Y scroll")] + public int Scr1ScrollY => scr1ScrollY; + [Port("REG_SCR2_X", 0x012)] + [BitDescription("SCR2 X scroll")] + public int Scr2ScrollX => scr2ScrollX; + [Port("REG_SCR2_Y", 0x013)] + [BitDescription("SCR2 Y scroll")] + public int Scr2ScrollY => scr2ScrollY; + [Port("REG_LCD_CTRL", 0x014)] + [BitDescription("LCD sleep mode; is LCD active?", 0)] + public bool LcdActive => lcdActive; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Sleep indicator", 0)] + public bool IconSleep => iconSleep; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Vertical orientation indicator", 1)] + public bool IconVertical => iconVertical; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Horizontal orientation indicator", 2)] + public bool IconHorizontal => iconHorizontal; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Auxiliary 1 (Small circle)", 3)] + public bool IconAux1 => iconAux1; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Auxiliary 2 (Medium circle)", 4)] + public bool IconAux2 => iconAux2; + [Port("REG_LCD_ICON", 0x015)] + [BitDescription("Auxiliary 3 (Big circle)", 5)] + public bool IconAux3 => iconAux3; + [Port("REG_LCD_VTOTAL", 0x016)] + [BitDescription("Display VTOTAL")] + public int VTotal => vtotal; + [Port("REG_LCD_VSYNC", 0x017)] + [BitDescription("VSYNC line position")] + public int VSync => vsync; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("H-blank timer enable", 0)] + public bool HBlankTimerEnable => hBlankTimer.Enable; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("H-blank timer mode; is repeating?", 1)] + public bool HBlankTimerRepeating => hBlankTimer.Repeating; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("V-blank timer enable", 2)] + public bool VBlankTimerEnable => vBlankTimer.Enable; + [Port("REG_TMR_CTRL", 0x0A2)] + [BitDescription("V-blank timer mode; is repeating?", 3)] + public bool VBlankTimerRepeating => vBlankTimer.Repeating; + [Port("REG_HTMR_FREQ", 0x0A4, 0x0A5)] + [BitDescription("H-blank timer frequency")] + public ushort HBlankTimerFrequency => hBlankTimer.Frequency; + [Port("REG_VTMR_FREQ", 0x0A6, 0x0A7)] + [BitDescription("V-blank timer frequency")] + public ushort VBlankTimerFrequency => vBlankTimer.Frequency; + [Port("REG_HTMR_CTR", 0x0A8, 0x0A9)] + [BitDescription("H-blank timer counter")] + public ushort HBlankTimerCounter => hBlankTimer.Counter; + [Port("REG_VTMR_CTR", 0x0AA, 0x0AB)] + [BitDescription("V-blank timer counter")] + public ushort VBlankTimerCounter => vBlankTimer.Counter; + + // TODO: reorganize palmono stuff & add attributes + + public byte[] PalMonoPools => palMonoPools; + public byte[][] PalMonoData => palMonoData; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs.meta new file mode 100644 index 0000000..0370aac --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayControllerCommon.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1a27fcff4fc28e846845555e4cd903cd \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs new file mode 100644 index 0000000..c94518c --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs @@ -0,0 +1,40 @@ +namespace StoicGoose.Core.Display +{ + public class DisplayTimer + { + public bool Enable { get; set; } + public bool Repeating { get; set; } + public ushort Frequency { get; set; } + + public ushort Counter { get; set; } + + public DisplayTimer() + { + Reset(); + } + + public void Reset() + { + Enable = Repeating = false; + Frequency = Counter = 0; + } + + public void Reload() + { + Counter = Frequency; + } + + public bool Step() + { + var counterNew = (ushort)(Counter - 1); + + if (Enable && Counter != 0) + { + Counter = counterNew; + if (Repeating && Counter == 0) + Reload(); + } + return counterNew == 0; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs.meta new file mode 100644 index 0000000..e23e0f0 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayTimer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 25ad8c5efc6af8d45b2500b9c3411df0 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs new file mode 100644 index 0000000..13597c0 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs @@ -0,0 +1,65 @@ +using System; +using StoicGoose.Core.Interfaces; + +namespace StoicGoose.Core.Display +{ + public static class DisplayUtilities + { + // TODO: WSC high contrast mode + + private static ushort ReadMemory16(IMachine machine, uint address) => (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + private static uint ReadMemory32(IMachine machine, uint address) => (uint)(machine.ReadMemory(address + 3) << 24 | machine.ReadMemory(address + 2) << 16 | machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + + public static byte ReadPixel(IMachine machine, ushort tile, int y, int x, bool isPacked, bool is4bpp, bool isColor) + { + /* http://perfectkiosk.net/stsws.html#color_mode */ + + /* WonderSwan OR Color/Crystal in 2bpp mode */ + if (!isColor || (isColor && !is4bpp)) + { + var data = ReadMemory16(machine, (uint)(0x2000 + (tile << 4) + ((y % 8) << 1))); + return (byte)((((data >> 15 - (x % 8)) & 0b1) << 1 | ((data >> 7 - (x % 8)) & 0b1)) & 0b11); + } + + /* WonderSwan Color/Crystal in 4bpp mode */ + else if (isColor && is4bpp) + { + /* 4bpp planar mode */ + if (!isPacked) + { + var data = ReadMemory32(machine, (uint)(0x4000 + ((tile & 0x03FF) << 5) + ((y % 8) << 2))); + return (byte)((((data >> 31 - (x % 8)) & 0b1) << 3 | ((data >> 23 - (x % 8)) & 0b1) << 2 | ((data >> 15 - (x % 8)) & 0b1) << 1 | ((data >> 7 - (x % 8)) & 0b1)) & 0b1111); + } + + /* 4bpp packed mode */ + else if (isPacked) + { + var data = machine.ReadMemory((ushort)(0x4000 + ((tile & 0x03FF) << 5) + ((y % 8) << 2) + ((x % 8) >> 1))); + return (byte)((data >> 4 - (((x % 8) & 0b1) << 2)) & 0b1111); + } + } + + throw new Exception("Invalid display controller configuration"); + } + + public static ushort ReadColor(IMachine machine, byte paletteIdx, byte colorIdx) + { + var address = (uint)(0x0FE00 + (paletteIdx << 5) + (colorIdx << 1)); + return (ushort)(machine.ReadMemory(address + 1) << 8 | machine.ReadMemory(address)); + } + + private static byte DuplicateBits(int value) => (byte)((value & 0b1111) | (value & 0b1111) << 4); + + public static (byte r, byte g, byte b) GeneratePixel(byte data) => (DuplicateBits(data), DuplicateBits(data), DuplicateBits(data)); + public static (byte r, byte g, byte b) GeneratePixel(ushort data) => (DuplicateBits(data >> 8), DuplicateBits(data >> 4), DuplicateBits(data >> 0)); + + public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, int x, int y, int stride) => CopyPixel(pixel, data, ((y * stride) + x) * 4); + public static void CopyPixel((byte r, byte g, byte b) pixel, byte[] data, long address) + { + data[address + 0] = pixel.r; + data[address + 1] = pixel.g; + data[address + 2] = pixel.b; + data[address + 3] = 255; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs.meta new file mode 100644 index 0000000..75587f1 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/DisplayUtilities.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3ef0eca0ad43a254f80fdccdc5891b74 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs new file mode 100644 index 0000000..3ecba73 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs @@ -0,0 +1,259 @@ +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Display +{ + public sealed class SphinxDisplayController : DisplayControllerCommon + { + // TODO: reimplement high contrast mode; also, get a WSC, figure out how it's supposed to look? + + /* REG_BACK_COLOR */ + byte backColorPalette; + /* REG_LCD_CTRL */ + bool lcdContrastHigh; + /* REG_DISP_MODE */ + bool displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet; + + public SphinxDisplayController(IMachine machine) : base(machine) { } + + protected override void ResetRegisters() + { + base.ResetRegisters(); + + backColorPalette = 0; + lcdContrastHigh = false; + displayPackedFormatSet = display4bppFlagSet = displayColorFlagSet = false; + } + + protected override void RenderSleep(int y, int x) + { + DisplayUtilities.CopyPixel((0, 0, 0), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderBackColor(int y, int x) + { + if (displayColorFlagSet) + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, backColorPalette, backColorIndex)), outputFramebuffer, x, y, HorizontalDisp); + else + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[backColorIndex & 0b0111])), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderSCR1(int y, int x) + { + if (!scr1Enable) return; + + var scrollX = (x + scr1ScrollX) & 0xFF; + var scrollY = (y + scr1ScrollY) & 0xFF; + + var mapOffset = (uint)((scr1Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1)); + var attribs = ReadMemory16(mapOffset); + var tileNum = (ushort)((attribs & 0x01FF) | (displayColorFlagSet ? (((attribs >> 13) & 0b1) << 9) : 0)); + var tilePal = (byte)((attribs >> 9) & 0b1111); + + var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet); + + var isOpaque = (!display4bppFlagSet && !IsBitSet(tilePal, 2)) || pixelColor != 0; + if (!isOpaque) return; + + if (displayColorFlagSet) + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, tilePal, pixelColor)), outputFramebuffer, x, y, HorizontalDisp); + else + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderSCR2(int y, int x) + { + if (!scr2Enable) return; + + var scrollX = (x + scr2ScrollX) & 0xFF; + var scrollY = (y + scr2ScrollY) & 0xFF; + + var mapOffset = (uint)((scr2Base << 11) | ((scrollY >> 3) << 6) | ((scrollX >> 3) << 1)); + var attribs = ReadMemory16(mapOffset); + var tileNum = (ushort)((attribs & 0x01FF) | (displayColorFlagSet ? (((attribs >> 13) & 0b1) << 9) : 0)); + var tilePal = (byte)((attribs >> 9) & 0b1111); + + var isVisible = !scr2WindowEnable || (scr2WindowEnable && ((!scr2WindowDisplayOutside && IsInsideSCR2Window(y, x)) || (scr2WindowDisplayOutside && IsOutsideSCR2Window(y, x)))); + if (!isVisible) return; + + var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, scrollY ^ (((attribs >> 15) & 0b1) * 7), scrollX ^ (((attribs >> 14) & 0b1) * 7), displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet); + + var isOpaque = (!display4bppFlagSet && !IsBitSet(tilePal, 2)) || pixelColor != 0; + if (!isOpaque) return; + + isUsedBySCR2[(y * HorizontalDisp) + x] = true; + + if (displayColorFlagSet) + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, tilePal, pixelColor)), outputFramebuffer, x, y, HorizontalDisp); + else + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp); + } + + protected override void RenderSprites(int y, int x) + { + if (!sprEnable) return; + + if (x == 0) + { + activeSpriteCountOnLine = 0; + for (var i = 0; i < spriteCountNextFrame; i++) + { + var spriteY = (spriteData[i] >> 16) & 0xFF; + if ((byte)(y - spriteY) <= 7 && activeSpriteCountOnLine < maxSpritesPerLine) + activeSpritesOnLine[activeSpriteCountOnLine++] = spriteData[i]; + } + } + + for (var i = 0; i < activeSpriteCountOnLine; i++) + { + var activeSprite = activeSpritesOnLine[i]; + + var spriteX = (activeSprite >> 24) & 0xFF; + if (x < 0 || x >= HorizontalDisp || (byte)(x - spriteX) > 7) continue; + + var windowDisplayOutside = ((activeSprite >> 12) & 0b1) == 0b1; + if (!sprWindowEnable || (sprWindowEnable && (windowDisplayOutside != IsInsideSPRWindow(y, x)))) + { + var tileNum = (ushort)(activeSprite & 0x01FF); + var tilePal = (byte)((activeSprite >> 9) & 0b111); + var priorityAboveSCR2 = ((activeSprite >> 13) & 0b1) == 0b1; + var spriteY = (activeSprite >> 16) & 0xFF; + + var isVisible = !isUsedBySCR2[(y * HorizontalDisp) + x] || priorityAboveSCR2; + if (!isVisible) continue; + + var pixelColor = DisplayUtilities.ReadPixel(machine, tileNum, (byte)((y - spriteY) ^ (((activeSprite >> 15) & 0b1) * 7)), (byte)((x - spriteX) ^ (((activeSprite >> 14) & 0b1) * 7)), displayPackedFormatSet, display4bppFlagSet, displayColorFlagSet); + + var isOpaque = (!display4bppFlagSet && !IsBitSet(tilePal, 2)) || pixelColor != 0; + if (!isOpaque) continue; + + tilePal += 8; + + if (displayColorFlagSet) + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel(DisplayUtilities.ReadColor(machine, tilePal, pixelColor)), outputFramebuffer, x, y, HorizontalDisp); + else + DisplayUtilities.CopyPixel(DisplayUtilities.GeneratePixel((byte)(15 - palMonoPools[palMonoData[tilePal][pixelColor & 0b11]])), outputFramebuffer, x, y, HorizontalDisp); + } + } + } + + public override byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x01: + /* REG_BACK_COLOR */ + retVal |= (byte)((backColorIndex & 0b1111) << 0); + retVal |= (byte)((backColorPalette & 0b1111) << 4); + break; + + case 0x04: + /* REG_SPR_BASE */ + retVal |= (byte)(sprBase & (displayColorFlagSet ? 0b111111 : 0b011111)); + break; + + case 0x07: + /* REG_MAP_BASE */ + retVal |= (byte)((scr1Base & (displayColorFlagSet ? 0b1111 : 0b0111)) << 0); + retVal |= (byte)((scr2Base & (displayColorFlagSet ? 0b1111 : 0b0111)) << 4); + break; + + case 0x14: + /* REG_LCD_CTRL */ + ChangeBit(ref retVal, 0, lcdActive); + ChangeBit(ref retVal, 1, lcdContrastHigh); + break; + + case 0x60: + /* REG_DISP_MODE */ + ChangeBit(ref retVal, 5, displayPackedFormatSet); + ChangeBit(ref retVal, 6, display4bppFlagSet); + ChangeBit(ref retVal, 7, displayColorFlagSet); + break; + + default: + /* Fall through to common */ + retVal = base.ReadPort(port); + break; + } + + return retVal; + } + + public override void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x01: + /* REG_BACK_COLOR */ + backColorIndex = (byte)((value >> 0) & 0b1111); + backColorPalette = (byte)((value >> 4) & 0b1111); + break; + + case 0x04: + /* REG_SPR_BASE */ + sprBase = (byte)(value & (displayColorFlagSet ? 0b111111 : 0b011111)); + break; + + case 0x07: + /* REG_MAP_BASE */ + scr1Base = (byte)((value >> 0) & (displayColorFlagSet ? 0b1111 : 0b0111)); + scr2Base = (byte)((value >> 4) & (displayColorFlagSet ? 0b1111 : 0b0111)); + break; + + case 0x14: + /* REG_LCD_CTRL */ + lcdActive = IsBitSet(value, 0); + lcdContrastHigh = IsBitSet(value, 1); + break; + + case 0x60: + /* REG_DISP_MODE */ + displayPackedFormatSet = IsBitSet(value, 5); + display4bppFlagSet = IsBitSet(value, 6); + displayColorFlagSet = IsBitSet(value, 7); + break; + + default: + /* Fall through to common */ + base.WritePort(port, value); + break; + } + } + + [Port("REG_BACK_COLOR", 0x001)] + [BitDescription("Background color index", 0, 3)] + public override byte BackColorIndex => backColorIndex; + [Port("REG_BACK_COLOR", 0x001)] + [BitDescription("Background color palette", 4, 7)] + public byte BackColorPalette => backColorPalette; + [Port("REG_SPR_BASE", 0x004)] + [BitDescription("Sprite table base address", 0, 5)] + [Format("X4", 9)] + public override int SprBase => sprBase; + [Port("REG_MAP_BASE", 0x007)] + [BitDescription("SCR1 base address", 0, 3)] + [Format("X4", 11)] + public override int Scr1Base => scr1Base; + [Port("REG_MAP_BASE", 0x007)] + [BitDescription("SCR2 base address", 4, 7)] + [Format("X4", 11)] + public override int Scr2Base => scr2Base; + [Port("REG_LCD_CTRL", 0x014)] + [BitDescription("LCD contrast setting; high contrast?", 1)] + public bool LcdContrastHigh => lcdContrastHigh; + [Port("REG_DISP_MODE", 0x060)] + [BitDescription("Tile format; is packed format?", 5)] + public bool DisplayPackedFormatSet => displayPackedFormatSet; + [Port("REG_DISP_MODE", 0x060)] + [BitDescription("Tile bits-per-pixel; is 4bpp?", 6)] + public bool Display4bppFlagSet => display4bppFlagSet; + [Port("REG_DISP_MODE", 0x060)] + [BitDescription("Display color mode; is color?", 7)] + public bool DisplayColorFlagSet => displayColorFlagSet; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs.meta new file mode 100644 index 0000000..ca14230 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Display/SphinxDisplayController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: db70409b0ab432c438c40e9b0d82e082 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs.meta new file mode 100644 index 0000000..b2bf5e1 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af8d3a9a00752da4496e02fe3b303d68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs new file mode 100644 index 0000000..4a695b2 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs @@ -0,0 +1,204 @@ +using System; + +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.EEPROMs +{ + public sealed class EEPROM : IPortAccessComponent + { + readonly byte[] contents = default; + readonly int numAddressBits = 0; + + bool eraseWriteEnable = false; + + byte dataLo, dataHi, addressLo, addressHi, statusCmd; + + public EEPROM(int size, int addressBits) + { + contents = new byte[size]; + numAddressBits = addressBits; + } + + public void Reset() + { + dataLo = dataHi = 0; + addressLo = addressHi = 0; + statusCmd = 0; + } + + public void Shutdown() + { + // + } + + public void LoadContents(byte[] data) + { + if (data.Length != contents.Length) + throw new Exception("Data size mismatch error"); + + Buffer.BlockCopy(data, 0, contents, 0, data.Length); + } + + public byte[] GetContents() + { + return contents; + } + + public void Program(int address, byte value) + { + contents[address & (contents.Length - 1)] = value; + } + + private void BeginAccess() + { + var addressHiLo = (addressHi << 8) | addressLo; + + var address = (addressHiLo & ((1 << numAddressBits) - 1)) << 1; + var opcode = (addressHiLo >> (numAddressBits + 0)) & 0b11; + var extOpcode = (addressHiLo >> (numAddressBits - 2)) & 0b11; // if opcode == 0, then extended + var start = ((addressHiLo >> (numAddressBits + 2)) & 0b1) == 0b1; + + // only one bit may be set + var requestBitsSet = 0; + for (var i = 4; i < 8; i++) requestBitsSet += (statusCmd >> i) & 0b1; + if (requestBitsSet != 1) return; + + switch ((statusCmd >> 4) & 0b1111) + { + /* Read request? */ + case 0b0001: + PerformAccess(start, opcode, extOpcode, address); + ChangeBit(ref statusCmd, 0, true); + ChangeBit(ref statusCmd, 4, false); + break; + + /* Write request? */ + case 0b0010: + PerformAccess(start, opcode, extOpcode, address); + ChangeBit(ref statusCmd, 1, true); + ChangeBit(ref statusCmd, 5, false); + break; + + /* Erase or misc request? */ + case 0b0100: + PerformAccess(start, opcode, extOpcode, address); + ChangeBit(ref statusCmd, 2, true); + ChangeBit(ref statusCmd, 6, false); + break; + + /* Reset request? */ + case 0b1000: + Reset(); + ChangeBit(ref statusCmd, 3, true); + ChangeBit(ref statusCmd, 7, false); + break; + } + } + + private void PerformAccess(bool start, int opcode, int extOpcode, int address) + { + if (!start) return; + + switch (opcode) + { + /* EWEN/ERAL/WRAL/EWDS */ + case 0b00: + { + switch (extOpcode) + { + /* EWDS */ + case 0b00: + eraseWriteEnable = false; + break; + + /* WRAL */ + case 0b01: + if (eraseWriteEnable) + { + for (var i = 0; i < contents.Length; i += 2) + { + contents[i + 0] = dataLo; + contents[i + 1] = dataHi; + } + } + break; + + /* ERAL */ + case 0b10: + if (eraseWriteEnable) + { + for (var i = 0; i < contents.Length; i++) + contents[i] = 0xFF; + } + break; + + /* EWEN */ + case 0b11: + eraseWriteEnable = true; + break; + } + } + break; + + /* WRITE */ + case 0b01: + if (eraseWriteEnable) + { + contents[address + 0] = dataLo; + contents[address + 1] = dataHi; + } + break; + + /* READ */ + case 0b10: + dataLo = contents[address + 0]; + dataHi = contents[address + 1]; + break; + + /* ERASE */ + case 0b11: + if (eraseWriteEnable) + { + dataLo = contents[address + 0]; + contents[address + 0] = 0xFF; + dataHi = contents[address + 1]; + contents[address + 1] = 0xFF; + } + break; + } + } + + public byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x00: retVal = dataLo; break; + case 0x01: retVal = dataHi; break; + case 0x02: retVal = addressLo; break; + case 0x03: retVal = addressHi; break; + case 0x04: retVal = (byte)(statusCmd & 0b0011); break; + } + + return retVal; + } + + public void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x00: dataLo = value; break; + case 0x01: dataHi = value; break; + case 0x02: addressLo = value; break; + case 0x03: addressHi = value; break; + case 0x04: + statusCmd = (byte)((statusCmd & 0b00001111) | (value & 0b11110000)); + BeginAccess(); + break; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs.meta new file mode 100644 index 0000000..c1f0962 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/EEPROMs/EEPROM.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3ce5cac210519e94a88dff895ab51d1e \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces.meta new file mode 100644 index 0000000..55b0423 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ca27119fa51e6604d92b9801e45d5b41 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs new file mode 100644 index 0000000..530b502 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs @@ -0,0 +1,8 @@ +namespace StoicGoose.Core.Interfaces +{ + public interface IComponent + { + void Reset(); + void Shutdown(); + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs.meta new file mode 100644 index 0000000..d5ac176 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fbe5f8c7b7960364a905f23a70f22e2b \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs new file mode 100644 index 0000000..0d724a4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +using StoicGoose.Core.Cartridges; +using StoicGoose.Core.CPU; +using StoicGoose.Core.Display; +using StoicGoose.Core.EEPROMs; +using StoicGoose.Core.Sound; + +namespace StoicGoose.Core.Interfaces +{ + public interface IMachine + { + static IEnumerable GetMachineTypes() => Assembly.GetAssembly(typeof(IMachine)).GetTypes().Where(x => !x.IsInterface && !x.IsAbstract && x.IsAssignableTo(typeof(IMachine))); + + string Manufacturer { get; } + string Model { get; } + + int ScreenWidth { get; } + int ScreenHeight { get; } + double RefreshRate { get; } + string GameControls { get; } + string HardwareControls { get; } + string VerticalControlRemap { get; } + + string InternalEepromDefaultUsername { get; } + Dictionary InternalEepromDefaultData { get; } + + Cartridge Cartridge { get; } + V30MZ Cpu { get; } + DisplayControllerCommon DisplayController { get; } + SoundControllerCommon SoundController { get; } + EEPROM InternalEeprom { get; } + + Func<(List buttonsPressed, List buttonsHeld)> ReceiveInput { get; set; } + + Func ReadMemoryCallback { get; set; } + Action WriteMemoryCallback { get; set; } + Func ReadPortCallback { get; set; } + Action WritePortCallback { get; set; } + Func RunStepCallback { get; set; } + + void Initialize(); + void Reset(); + void Shutdown(); + + void RunFrame(); + void RunLine(); + void RunStep(); + + void LoadBootstrap(byte[] data); + bool IsBootstrapLoaded { get; } + bool UseBootstrap { get; set; } + void LoadInternalEeprom(byte[] data); + void LoadRom(byte[] data); + void LoadSaveData(byte[] data); + + byte[] GetInternalEeprom(); + byte[] GetSaveData(); + + byte ReadMemory(uint address); + void WriteMemory(uint address, byte value); + byte ReadPort(ushort port); + void WritePort(ushort port, byte value); + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs.meta new file mode 100644 index 0000000..7ec97ba --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMachine.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f0af901bd4adf4f449a3ec347bcd46ae \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs new file mode 100644 index 0000000..1297847 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs @@ -0,0 +1,8 @@ +namespace StoicGoose.Core.Interfaces +{ + interface IMemoryAccessComponent : IComponent + { + byte ReadMemory(uint address); + void WriteMemory(uint address, byte value); + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs.meta new file mode 100644 index 0000000..3f12308 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IMemoryAccessComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7bbbf381ccd119f4291d1e8671a4e9b2 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs new file mode 100644 index 0000000..5c9f035 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs @@ -0,0 +1,8 @@ +namespace StoicGoose.Core.Interfaces +{ + interface IPortAccessComponent : IComponent + { + byte ReadPort(ushort port); + void WritePort(ushort port, byte value); + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs.meta new file mode 100644 index 0000000..59088af --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Interfaces/IPortAccessComponent.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d81205bc9412fb24e9905b414e4b6b30 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines.meta new file mode 100644 index 0000000..b17c2d4 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 35bba939b8459124c8b129925c4cc47d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs new file mode 100644 index 0000000..6e0aa92 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; + +using StoicGoose.Common.Attributes; +using StoicGoose.Common.Utilities; +using StoicGoose.Core.Cartridges; +using StoicGoose.Core.CPU; +using StoicGoose.Core.Display; +using StoicGoose.Core.EEPROMs; +using StoicGoose.Core.Interfaces; +using StoicGoose.Core.Serial; +using StoicGoose.Core.Sound; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Machines +{ + public abstract class MachineCommon : IMachine, IMemoryAccessComponent, IPortAccessComponent + { + // http://daifukkat.su/docs/wsman/ + + public abstract string Manufacturer { get; } + public abstract string Model { get; } + + public int ScreenWidth => DisplayControllerCommon.ScreenWidth; + public int ScreenHeight => DisplayControllerCommon.ScreenHeight; + public double RefreshRate => DisplayControllerCommon.VerticalClock; + public string GameControls => "Start, B, A, X1, X2, X3, X4, Y1, Y2, Y3, Y4"; + public string HardwareControls => "Volume"; + public string VerticalControlRemap => "X1=Y2, X2=Y3, X3=Y4, X4=Y1, Y1=X2, Y2=X3, Y3=X4, Y4=X1"; + + public abstract string InternalEepromDefaultUsername { get; } + public abstract Dictionary InternalEepromDefaultData { get; } + + public const double MasterClock = 12288000.0; /* 12.288 MHz xtal */ + public const double CpuClock = MasterClock / 4.0; /* /4 = 3.072 MHz */ + + public abstract int InternalRamSize { get; } + public uint InternalRamMask { get; protected set; } = 0; + public byte[] InternalRam { get; protected set; } = default; + + public Cartridge Cartridge { get; protected set; } = new(); + public V30MZ Cpu { get; protected set; } = default; + public DisplayControllerCommon DisplayController { get; protected set; } = default; + public SoundControllerCommon SoundController { get; protected set; } = default; + public EEPROM InternalEeprom { get; protected set; } = default; + public Bootstrap BootstrapRom { get; protected set; } = default; + public SerialPort Serial { get; protected set; } = default; + + public abstract int InternalEepromSize { get; } + public abstract int InternalEepromAddressBits { get; } + + public abstract int BootstrapRomAddress { get; } + public abstract int BootstrapRomSize { get; } + + public Func<(List buttonsPressed, List buttonsHeld)> ReceiveInput { get; set; } = default; + + public Func ReadMemoryCallback { get; set; } = default; + public Action WriteMemoryCallback { get; set; } = default; + public Func ReadPortCallback { get; set; } = default; + public Action WritePortCallback { get; set; } = default; + public Func RunStepCallback { get; set; } = default; + + protected bool cancelFrameExecution = false; + + public int CurrentClockCyclesInLine { get; protected set; } = 0; + public int CurrentClockCyclesInFrame { get; protected set; } = 0; + + public int TotalClockCyclesInFrame { get; protected set; } = 0; + + /* REG_HW_FLAGS */ + protected bool cartEnable, isWSCOrGreater, is16BitExtBus, cartRom1CycleSpeed, builtInSelfTestOk; + /* REG_KEYPAD */ + protected bool keypadYEnable, keypadXEnable, keypadButtonEnable; + /* REG_INT_xxx */ + protected byte interruptBase, interruptEnable, interruptStatus; + + public bool IsBootstrapLoaded { get; private set; } = false; + public bool UseBootstrap { get; set; } = false; + + public virtual void Initialize() + { + if (InternalRamSize == -1) throw new Exception("Internal RAM size not set"); + + InternalRamMask = (uint)(InternalRamSize - 1); + InternalRam = new byte[InternalRamSize]; + + Cpu = new(this); + InternalEeprom = new(InternalEepromSize, InternalEepromAddressBits); + BootstrapRom = new(BootstrapRomSize); + Serial = new(); + + InitializeEepromToDefaults(); + + Log.WriteEvent(LogSeverity.Information, this, "Machine initialized."); + } + + public virtual void Reset() + { + for (var i = 0; i < InternalRam.Length; i++) InternalRam[i] = 0; + + Cartridge?.Reset(); + Cpu?.Reset(); + DisplayController?.Reset(); + SoundController?.Reset(); + InternalEeprom?.Reset(); + Serial?.Reset(); + + CurrentClockCyclesInFrame = 0; + CurrentClockCyclesInLine = 0; + TotalClockCyclesInFrame = (int)Math.Round(CpuClock / DisplayControllerCommon.VerticalClock); + + ResetRegisters(); + + Log.WriteEvent(LogSeverity.Information, this, "Machine reset."); + } + + public virtual void ResetRegisters() + { + cartEnable = !IsBootstrapLoaded || !UseBootstrap; + is16BitExtBus = true; + cartRom1CycleSpeed = false; + builtInSelfTestOk = true; + + keypadYEnable = keypadXEnable = keypadButtonEnable = false; + + interruptBase = interruptEnable = interruptStatus = 0; + } + + public virtual void Shutdown() + { + Cartridge?.Shutdown(); + Cpu?.Shutdown(); + DisplayController?.Shutdown(); + SoundController?.Shutdown(); + InternalEeprom?.Shutdown(); + Serial?.Shutdown(); + + Log.WriteEvent(LogSeverity.Information, this, "Machine shutdown."); + } + + protected virtual void InitializeEepromToDefaults() + { + var data = ConvertUsernameForEeprom(InternalEepromDefaultUsername); + for (var i = 0; i < data.Length; i++) InternalEeprom.Program(0x60 + i, data[i]); // Username (0x60-0x6F, max 16 characters) + foreach (var (address, value) in InternalEepromDefaultData) InternalEeprom.Program(address, value); + } + + private static byte[] ConvertUsernameForEeprom(string name) + { + var data = new byte[16]; + for (var i = 0; i < data.Length; i++) + { + var c = i < name.Length ? name[i] : ' '; + if (c == ' ') data[i] = (byte)(c - ' ' + 0x00); + else if (c >= '0' && c <= '9') data[i] = (byte)(c - '0' + 0x01); + else if (c >= 'A' && c <= 'Z') data[i] = (byte)(c - 'A' + 0x0B); + else if (c >= 'a' && c <= 'b') data[i] = (byte)(c - 'A' + 0x0B); + else if (c == '♥') data[i] = (byte)(c - '♥' + 0x25); + else if (c == '♪') data[i] = (byte)(c - '♪' + 0x26); + else if (c == '+') data[i] = (byte)(c - '+' + 0x27); + else if (c == '-') data[i] = (byte)(c - '-' + 0x28); + else if (c == '?') data[i] = (byte)(c - '?' + 0x29); + else if (c == '.') data[i] = (byte)(c - '.' + 0x2A); + else data[i] = 0x00; + } + return data; + } + + public void RunFrame() + { + while (CurrentClockCyclesInFrame < TotalClockCyclesInFrame) + { + RunLine(); + + if (cancelFrameExecution) return; + } + + CurrentClockCyclesInFrame -= TotalClockCyclesInFrame; + + _ = ReceiveInput?.Invoke(); + } + + public void RunLine() + { + while (CurrentClockCyclesInLine < DisplayControllerCommon.HorizontalTotal) + { + RunStep(); + + if (cancelFrameExecution) return; + } + + CurrentClockCyclesInFrame += CurrentClockCyclesInLine; + CurrentClockCyclesInLine = 0; + } + + public abstract void RunStep(); + + protected void RaiseInterrupt(int number) + { + if (!IsBitSet(interruptEnable, number)) return; + ChangeBit(ref interruptStatus, number, true); + } + + protected void LowerInterrupt(int number) + { + ChangeBit(ref interruptStatus, number, false); + } + + protected void HandleInterrupts() + { + if (!Cpu.IsFlagSet(V30MZ.Flags.InterruptEnable)) return; + + for (var i = 7; i >= 0; i--) + { + if (!IsBitSet(interruptStatus, i)) continue; + + Cpu.IsHalted = false; + Cpu.Interrupt((interruptBase & 0b11111000) | i); + return; + } + } + + public void LoadBootstrap(byte[] data) + { + BootstrapRom.LoadRom(data); + + IsBootstrapLoaded = true; + } + + public void LoadInternalEeprom(byte[] data) + { + InternalEeprom.LoadContents(data); + } + + public void LoadRom(byte[] data) + { + Cartridge.LoadRom(data); + } + + public void LoadSaveData(byte[] data) + { + if (Cartridge.Metadata.IsSramSave) + Cartridge.LoadSram(data); + else if (Cartridge.Metadata.IsEepromSave) + Cartridge.LoadEeprom(data); + } + + public byte[] GetInternalEeprom() + { + return InternalEeprom.GetContents(); + } + + public byte[] GetSaveData() + { + if (Cartridge.Metadata != null) + { + if (Cartridge.Metadata.IsSramSave) + return Cartridge.GetSram(); + else if (Cartridge.Metadata.IsEepromSave) + return Cartridge.GetEeprom(); + } + + return Array.Empty(); + } + + public byte ReadMemory(uint address) + { + byte retVal; + + if (!cartEnable && BootstrapRom != null && address >= BootstrapRomAddress) + { + /* Bootstrap enabled */ + retVal = BootstrapRom.ReadMemory(address); + } + else + { + address &= 0xFFFFF; + + if ((address & 0xF0000) == 0x00000) + { + /* Internal RAM -- returns 0x90 if unmapped */ + if (address < InternalRamSize) + retVal = InternalRam[address & InternalRamMask]; + else + retVal = 0x90; + } + else + { + /* Cartridge */ + retVal = Cartridge.ReadMemory(address); + } + } + + if (ReadMemoryCallback != null) + retVal = ReadMemoryCallback.Invoke(address, retVal); + + return retVal; + } + + public void WriteMemory(uint address, byte value) + { + WriteMemoryCallback?.Invoke(address, value); + + address &= 0xFFFFF; + if ((address & 0xF0000) == 0x00000) + { + /* Internal RAM -- no effect if unmapped */ + if (address < InternalRamSize) + InternalRam[address & InternalRamMask] = value; + } + else if ((address & 0xF0000) == 0x10000) + { + /* Cartridge -- SRAM only, other writes not emitted */ + Cartridge.WriteMemory(address, value); + } + } + + public abstract byte ReadPort(ushort port); + public abstract void WritePort(ushort port, byte value); + + [Port("REG_HW_FLAGS", 0x0A0)] + [BitDescription("BIOS lockout; is cartridge mapped?", 0)] + public bool CartEnable => cartEnable; + [Port("REG_HW_FLAGS", 0x0A0)] + [BitDescription("System type; is WSC or greater?", 1)] + public bool IsWSCOrGreater => isWSCOrGreater; + [Port("REG_HW_FLAGS", 0x0A0)] + [BitDescription("External bus width; is 16-bit bus?", 2)] + public bool Is16BitExtBus => is16BitExtBus; + [Port("REG_HW_FLAGS", 0x0A0)] + [BitDescription("Cartridge ROM speed; is 1-cycle?", 3)] + public bool CartRom1CycleSpeed => cartRom1CycleSpeed; + [Port("REG_HW_FLAGS", 0x0A0)] + [BitDescription("Built-in self test passed", 7)] + public bool BuiltInSelfTestOk => builtInSelfTestOk; + + [Port("REG_KEYPAD", 0x0B5)] + [BitDescription("Y keys check enabled", 4)] + public bool KeypadYEnable => keypadYEnable; + [Port("REG_KEYPAD", 0x0B5)] + [BitDescription("X keys check enabled", 5)] + public bool KeypadXEnable => keypadXEnable; + [Port("REG_KEYPAD", 0x0B5)] + [BitDescription("Button check enabled", 6)] + public bool KeypadButtonEnable => keypadButtonEnable; + + [Port("REG_INT_BASE", 0x0B0)] + public abstract byte InterruptBase { get; } + [Port("REG_INT_ENABLE", 0x0B2)] + [BitDescription("Interrupt enable bitmask", 4)] + [Format("X2")] + public byte InterruptEnable => interruptEnable; + [Port("REG_INT_STATUS", 0x0B4)] + [BitDescription("Interrupt status bitmask", 4)] + [Format("X2")] + public byte InterruptStatus => interruptStatus; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs.meta new file mode 100644 index 0000000..7195c43 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/MachineCommon.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 961184224ac597c4281ef0e43aa48d68 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs new file mode 100644 index 0000000..d122b10 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs @@ -0,0 +1,303 @@ +using System.Collections.Generic; + +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Display; +using StoicGoose.Core.Serial; +using StoicGoose.Core.Sound; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Machines +{ + public partial class WonderSwan : MachineCommon + { + public override string Manufacturer => "Bandai"; + public override string Model => "WonderSwan"; + + public override string InternalEepromDefaultUsername => "WONDERSWAN"; + public override Dictionary InternalEepromDefaultData => new() + { + { 0x70, 0x19 }, // Year of birth [just for fun, here set to original WS release date; new systems probably had no date set?] + { 0x71, 0x99 }, // "" + { 0x72, 0x03 }, // Month of birth [again, WS release for fun] + { 0x73, 0x04 }, // Day of birth [and again] + { 0x74, 0x00 }, // Sex [set to ?] + { 0x75, 0x00 }, // Blood type [set to ?] + + { 0x76, 0x00 }, // Last game played, publisher ID [set to presumably none] + { 0x77, 0x00 }, // "" + { 0x78, 0x00 }, // Last game played, game ID [set to presumably none] + { 0x79, 0x00 }, // "" + { 0x7A, 0x00 }, // Swan ID (see Mama Mitte) -- TODO: set to valid/random value? + { 0x7B, 0x00 }, // "" + { 0x7C, 0x00 }, // Number of different games played [set to presumably none] + { 0x7D, 0x00 }, // Number of times settings were changed [set to presumably none] + { 0x7E, 0x00 }, // Number of times powered on [set to presumably none] + { 0x7F, 0x00 } // "" + }; + + public override int InternalRamSize => 16 * 1024; + + public override int InternalEepromSize => 64 * 2; + public override int InternalEepromAddressBits => 6; + + public override int BootstrapRomAddress => 0xFF000; + public override int BootstrapRomSize => 0x1000; + + public override void Initialize() + { + DisplayController = new AswanDisplayController(this); + SoundController = new AswanSoundController(this, 44100, 2); + + base.Initialize(); + } + + public override void ResetRegisters() + { + isWSCOrGreater = false; + + base.ResetRegisters(); + } + + public override void RunStep() + { + if (RunStepCallback == null || RunStepCallback.Invoke() == false) + { + HandleInterrupts(); + + var currentCpuClockCycles = Cpu.Step(); + + var displayInterrupt = DisplayController.Step(currentCpuClockCycles); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.LineCompare)) RaiseInterrupt(4); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlankTimer)) RaiseInterrupt(5); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlank)) RaiseInterrupt(6); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.HBlankTimer)) RaiseInterrupt(7); + + SoundController.Step(currentCpuClockCycles); + + if (Cartridge.Step(currentCpuClockCycles)) RaiseInterrupt(2); + else LowerInterrupt(2); + + var serialInterrupt = Serial.Step(); + if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialSend)) RaiseInterrupt(0); + if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialRecieve)) RaiseInterrupt(3); + + CurrentClockCyclesInLine += currentCpuClockCycles; + + cancelFrameExecution = false; + } + else + cancelFrameExecution = true; + } + + public override byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + /* Display controller, etc. (H/V timers, DISP_MODE) */ + case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB): + retVal = DisplayController.ReadPort(port); + break; + + /* Sound controller */ + case var n when n >= 0x80 && n < 0xA0: + retVal = SoundController.ReadPort(port); + break; + + /* Serial port */ + case var n when n == 0xB1 || n == 0xB3: + retVal = Serial.ReadPort(port); + break; + + /* System controller */ + case 0xA0: + /* REG_HW_FLAGS */ + ChangeBit(ref retVal, 0, cartEnable); + ChangeBit(ref retVal, 1, false); + ChangeBit(ref retVal, 2, is16BitExtBus); + ChangeBit(ref retVal, 3, cartRom1CycleSpeed); + ChangeBit(ref retVal, 7, builtInSelfTestOk); + break; + + case 0xB0: + /* REG_INT_BASE */ + retVal = interruptBase; + retVal |= 0b11; + break; + + case 0xB2: + /* REG_INT_ENABLE */ + retVal = interruptEnable; + break; + + case 0xB4: + /* REG_INT_STATUS */ + retVal = interruptStatus; + break; + + case 0xB5: + /* REG_KEYPAD */ + ChangeBit(ref retVal, 4, keypadYEnable); + ChangeBit(ref retVal, 5, keypadXEnable); + ChangeBit(ref retVal, 6, keypadButtonEnable); + + /* Get input from UI */ + var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld; + if (buttonsHeld != null) + { + if (buttonsHeld.Count > 0) + RaiseInterrupt(1); + + if (keypadYEnable) + { + if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true); + if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true); + if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true); + if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true); + } + + if (keypadXEnable) + { + if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true); + if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true); + if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true); + if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true); + } + + if (keypadButtonEnable) + { + if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true); + if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true); + if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true); + } + } + break; + + case 0xB6: + /* REG_INT_ACK */ + retVal = 0x00; + break; + + case 0xB7: + /* ??? */ + retVal = 0x00; + break; + + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + /* REG_IEEP_DATA (low) */ + /* REG_IEEP_DATA (high) */ + /* REG_IEEP_ADDR (low) */ + /* REG_IEEP_ADDR (high) */ + /* REG_IEEP_CMD (write) */ + retVal = InternalEeprom.ReadPort((ushort)(port - 0xBA)); + break; + + /* Cartridge */ + case var n when n >= 0xC0 && n < 0x100: + retVal = Cartridge.ReadPort(port); + break; + + /* Unmapped */ + default: + retVal = 0x90; + break; + } + + if (ReadPortCallback != null) + retVal = ReadPortCallback.Invoke(port, retVal); + + return retVal; + } + + public override void WritePort(ushort port, byte value) + { + WritePortCallback?.Invoke(port, value); + + switch (port) + { + /* Display controller, etc. (H/V timers, DISP_MODE) */ + case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB): + DisplayController.WritePort(port, value); + break; + + /* Sound controller */ + case var n when n >= 0x80 && n < 0xA0: + SoundController.WritePort(port, value); + break; + + /* Serial port */ + case var n when n == 0xB1 || n == 0xB3: + Serial.WritePort(port, value); + break; + + /* System controller */ + case 0xA0: + /* REG_HW_FLAGS */ + if (!cartEnable) + cartEnable = IsBitSet(value, 0); + is16BitExtBus = IsBitSet(value, 2); + cartRom1CycleSpeed = IsBitSet(value, 3); + break; + + case 0xB0: + /* REG_INT_BASE */ + interruptBase = (byte)(value & 0b11111000); + break; + + case 0xB2: + /* REG_INT_ENABLE */ + interruptEnable = value; + break; + + case 0xB4: + /* REG_INT_STATUS -- read-only */ + break; + + case 0xB5: + /* REG_KEYPAD */ + keypadYEnable = IsBitSet(value, 4); + keypadXEnable = IsBitSet(value, 5); + keypadButtonEnable = IsBitSet(value, 6); + break; + + case 0xB6: + /* REG_INT_ACK */ + interruptStatus &= (byte)~(value & (0b11110010 | ~interruptEnable)); + break; + + case 0xB7: + /* ??? */ + break; + + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + /* REG_IEEP_DATA (low) */ + /* REG_IEEP_DATA (high) */ + /* REG_IEEP_ADDR (low) */ + /* REG_IEEP_ADDR (high) */ + /* REG_IEEP_STATUS (read) */ + InternalEeprom.WritePort((ushort)(port - 0xBA), value); + break; + + /* Cartridge */ + case var n when n >= 0xC0 && n < 0x100: + Cartridge.WritePort(port, value); + break; + } + } + + [Port("REG_INT_BASE", 0x0B0)] + [BitDescription("Interrupt base address", 3, 7)] + [Format("X4", 0)] + public override byte InterruptBase => interruptBase; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs.meta new file mode 100644 index 0000000..c6d1d16 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwan.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f3e696cb652b87242b1d85bfbc978b7b \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs new file mode 100644 index 0000000..828a41f --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs @@ -0,0 +1,367 @@ +using System.Collections.Generic; + +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Display; +using StoicGoose.Core.DMA; +using StoicGoose.Core.Serial; +using StoicGoose.Core.Sound; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Machines +{ + public partial class WonderSwanColor : MachineCommon + { + public override string Manufacturer => "Bandai"; + public override string Model => "WonderSwan Color"; + + public override string InternalEepromDefaultUsername => "WONDERSWANCOLOR"; + public override Dictionary InternalEepromDefaultData => new() + { + { 0x70, 0x20 }, // Year of birth [set to WSC release date for fun] + { 0x71, 0x00 }, // "" + { 0x72, 0x12 }, // Month of birth [again] + { 0x73, 0x09 }, // Day of birth [again] + { 0x74, 0x00 }, // Sex [?] + { 0x75, 0x00 }, // Blood type [?] + + { 0x76, 0x00 }, // Last game played, publisher ID [none] + { 0x77, 0x00 }, // "" + { 0x78, 0x00 }, // Last game played, game ID [none] + { 0x79, 0x00 }, // "" + { 0x7A, 0x00 }, // Swan ID (see Mama Mitte) -- TODO: set to valid/random value? + { 0x7B, 0x00 }, // "" + { 0x7C, 0x00 }, // Number of different games played [none] + { 0x7D, 0x00 }, // Number of times settings were changed [none] + { 0x7E, 0x00 }, // Number of times powered on [none] + { 0x7F, 0x00 } // "" + }; + + public override int InternalRamSize => 64 * 1024; + + public override int InternalEepromSize => 1024 * 2; + public override int InternalEepromAddressBits => 10; + + public override int BootstrapRomAddress => 0xFE000; + public override int BootstrapRomSize => 0x2000; + + public SphinxGeneralDMAController DmaController { get; protected set; } = default; + public SphinxSoundDMAController SoundDmaController { get; protected set; } = default; + + public override void Initialize() + { + DisplayController = new SphinxDisplayController(this); + SoundController = new SphinxSoundController(this, 44100, 2); + DmaController = new SphinxGeneralDMAController(this); + SoundDmaController = new SphinxSoundDMAController(this); + + base.Initialize(); + } + + public override void Reset() + { + DmaController.Reset(); + + base.Reset(); + } + + public override void ResetRegisters() + { + isWSCOrGreater = true; + + base.ResetRegisters(); + } + + public override void Shutdown() + { + DmaController.Shutdown(); + + base.Shutdown(); + } + + protected override void InitializeEepromToDefaults() + { + base.InitializeEepromToDefaults(); + + InternalEeprom.Program(0x83, (byte)(0b0 << 6 | SoundController.MaxMasterVolume & 0b11)); // Flags (low contrast, max volume) + } + + public override void RunStep() + { + if (RunStepCallback == null || RunStepCallback.Invoke() == false) + { + HandleInterrupts(); + + var currentCpuClockCycles = DmaController.IsActive ? DmaController.Step() : Cpu.Step(); + + var displayInterrupt = DisplayController.Step(currentCpuClockCycles); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.LineCompare)) RaiseInterrupt(4); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlankTimer)) RaiseInterrupt(5); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.VBlank)) RaiseInterrupt(6); + if (displayInterrupt.HasFlag(DisplayControllerCommon.DisplayInterrupts.HBlankTimer)) RaiseInterrupt(7); + + if (SoundDmaController.IsActive) + SoundDmaController.Step(currentCpuClockCycles); + + SoundController.Step(currentCpuClockCycles); + + if (Cartridge.Step(currentCpuClockCycles)) RaiseInterrupt(2); + else LowerInterrupt(2); + + var serialInterrupt = Serial.Step(); + if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialSend)) RaiseInterrupt(0); + if (serialInterrupt.HasFlag(SerialPort.SerialInterrupts.SerialRecieve)) RaiseInterrupt(3); + + CurrentClockCyclesInLine += currentCpuClockCycles; + + cancelFrameExecution = false; + } + else + cancelFrameExecution = true; + } + + public override byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + /* Display controller, etc. (H/V timers, DISP_MODE) */ + case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB): + retVal = DisplayController.ReadPort(port); + break; + + /* DMA controller */ + case var n when n >= 0x40 && n < 0x4A: + retVal = DmaController.ReadPort(port); + break; + + /* Sound DMA controller */ + case var n when n >= 0x4A && n < 0x53: + retVal = SoundDmaController.ReadPort(port); + break; + + /* Sound controller */ + case var n when (n >= 0x80 && n < 0xA0) || (n >= 0x6A && n <= 0x6B): + retVal = SoundController.ReadPort(port); + break; + + /* Serial port */ + case var n when n == 0xB1 || n == 0xB3: + retVal = Serial.ReadPort(port); + break; + + /* Misc system registers */ + case 0x62: + /* REG_WSC_SYSTEM */ + ChangeBit(ref retVal, 7, false); // not SwanCrystal + break; + + /* System controller */ + case 0xA0: + /* REG_HW_FLAGS */ + ChangeBit(ref retVal, 0, cartEnable); + ChangeBit(ref retVal, 1, true); + ChangeBit(ref retVal, 2, is16BitExtBus); + ChangeBit(ref retVal, 3, cartRom1CycleSpeed); + ChangeBit(ref retVal, 7, builtInSelfTestOk); + break; + + case 0xB0: + /* REG_INT_BASE */ + retVal = interruptBase; + break; + + case 0xB2: + /* REG_INT_ENABLE */ + retVal = interruptEnable; + break; + + case 0xB4: + /* REG_INT_STATUS */ + retVal = interruptStatus; + break; + + case 0xB5: + /* REG_KEYPAD */ + ChangeBit(ref retVal, 4, keypadYEnable); + ChangeBit(ref retVal, 5, keypadXEnable); + ChangeBit(ref retVal, 6, keypadButtonEnable); + + /* Get input from UI */ + var buttonsHeld = ReceiveInput?.Invoke().buttonsHeld; + if (buttonsHeld != null) + { + if (buttonsHeld.Count > 0) + RaiseInterrupt(1); + + if (keypadYEnable) + { + if (buttonsHeld.Contains("Y1")) ChangeBit(ref retVal, 0, true); + if (buttonsHeld.Contains("Y2")) ChangeBit(ref retVal, 1, true); + if (buttonsHeld.Contains("Y3")) ChangeBit(ref retVal, 2, true); + if (buttonsHeld.Contains("Y4")) ChangeBit(ref retVal, 3, true); + } + + if (keypadXEnable) + { + if (buttonsHeld.Contains("X1")) ChangeBit(ref retVal, 0, true); + if (buttonsHeld.Contains("X2")) ChangeBit(ref retVal, 1, true); + if (buttonsHeld.Contains("X3")) ChangeBit(ref retVal, 2, true); + if (buttonsHeld.Contains("X4")) ChangeBit(ref retVal, 3, true); + } + + if (keypadButtonEnable) + { + if (buttonsHeld.Contains("Start")) ChangeBit(ref retVal, 1, true); + if (buttonsHeld.Contains("A")) ChangeBit(ref retVal, 2, true); + if (buttonsHeld.Contains("B")) ChangeBit(ref retVal, 3, true); + } + } + break; + + case 0xB6: + /* REG_INT_ACK */ + retVal = 0x00; + break; + + case 0xB7: + /* ??? */ + retVal = 0x00; + break; + + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + /* REG_IEEP_DATA (low) */ + /* REG_IEEP_DATA (high) */ + /* REG_IEEP_ADDR (low) */ + /* REG_IEEP_ADDR (high) */ + /* REG_IEEP_CMD (write) */ + retVal = InternalEeprom.ReadPort((ushort)(port - 0xBA)); + break; + + /* Cartridge */ + case var n when n >= 0xC0 && n < 0x100: + retVal = Cartridge.ReadPort(port); + break; + + /* Unmapped */ + default: + retVal = 0x90; + break; + } + + if (ReadPortCallback != null) + retVal = ReadPortCallback.Invoke(port, retVal); + + return retVal; + } + + public override void WritePort(ushort port, byte value) + { + WritePortCallback?.Invoke(port, value); + + switch (port) + { + /* Display controller, etc. (H/V timers, DISP_MODE) */ + case var n when (n >= 0x00 && n < 0x40) || n == 0x60 || n == 0xA2 || (n >= 0xA4 && n <= 0xAB): + DisplayController.WritePort(port, value); + break; + + /* DMA controller */ + case var n when n >= 0x40 && n < 0x4A: + DmaController.WritePort(port, value); + break; + + /* Sound DMA controller */ + case var n when n >= 0x4A && n < 0x53: + SoundDmaController.WritePort(port, value); + break; + + /* Sound controller */ + case var n when (n >= 0x80 && n < 0xA0) || (n >= 0x6A && n <= 0x6B): + SoundController.WritePort(port, value); + break; + + /* Serial port */ + case var n when n == 0xB1 || n == 0xB3: + Serial.WritePort(port, value); + break; + + /* Misc system registers */ + case 0x62: + /* REG_WSC_SYSTEM */ + if (IsBitSet(value, 0)) + { + // TODO: power-off bit, stop emulation? + } + break; + + /* System controller */ + case 0xA0: + /* REG_HW_FLAGS */ + if (!cartEnable) + cartEnable = IsBitSet(value, 0); + is16BitExtBus = IsBitSet(value, 2); + cartRom1CycleSpeed = IsBitSet(value, 3); + break; + + case 0xB0: + /* REG_INT_BASE */ + interruptBase = (byte)(value & 0b11111110); + break; + + case 0xB2: + /* REG_INT_ENABLE */ + interruptEnable = value; + break; + + case 0xB4: + /* REG_INT_STATUS -- read-only */ + break; + + case 0xB5: + /* REG_KEYPAD */ + keypadYEnable = IsBitSet(value, 4); + keypadXEnable = IsBitSet(value, 5); + keypadButtonEnable = IsBitSet(value, 6); + break; + + case 0xB6: + /* REG_INT_ACK */ + interruptStatus &= (byte)~(value & (0b11110010 | ~interruptEnable)); + break; + + case 0xB7: + /* ??? */ + break; + + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + /* REG_IEEP_DATA (low) */ + /* REG_IEEP_DATA (high) */ + /* REG_IEEP_ADDR (low) */ + /* REG_IEEP_ADDR (high) */ + /* REG_IEEP_STATUS (read) */ + InternalEeprom.WritePort((ushort)(port - 0xBA), value); + break; + + /* Cartridge */ + case var n when n >= 0xC0 && n < 0x100: + Cartridge.WritePort(port, value); + break; + } + } + + [Port("REG_INT_BASE", 0x0B0)] + [BitDescription("Interrupt base address", 1, 7)] + [Format("X4", 0)] + public override byte InterruptBase => interruptBase; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs.meta new file mode 100644 index 0000000..6c103aa --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Machines/WonderSwanColor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8054a1a1d865d2e4ea3fa676c4de78dd \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial.meta new file mode 100644 index 0000000..77e284a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2fcb17a464660ae4fbecae852698c8ab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs new file mode 100644 index 0000000..054093b --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs @@ -0,0 +1,130 @@ +using System; + +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Serial +{ + public class SerialPort : IPortAccessComponent + { + // https://github.com/ares-emulator/ares/tree/709afef820914e3399425bb77cbc1baf895028a1/ares/ws/serial + + [Flags] + public enum SerialInterrupts + { + None = 0, + SerialSend = 1 << 0, + SerialRecieve = 1 << 1 + } + + int baudClock, txBitClock; + + /* REG_SER_DATA */ + protected byte serialData; + /* REG_SER_STATUS */ + protected bool enable, baudRateSelect, txEmpty, rxOverrun, rxFull; + + public void Reset() + { + serialData = 0; + enable = baudRateSelect = rxOverrun = rxFull = false; + } + + public void Shutdown() + { + /* Nothing to do... */ + } + + public SerialInterrupts Step() + { + if (!enable) return SerialInterrupts.None; + + if (!baudRateSelect && ++baudClock < 4) return SerialInterrupts.None; + baudClock = 0; + + // STUB + if (!txEmpty) + { + if (++txBitClock == 9) + { + txBitClock = 0; + txEmpty = true; + } + } + + var interrupt = SerialInterrupts.None; + if (txEmpty) interrupt |= SerialInterrupts.SerialSend; + if (rxFull) interrupt |= SerialInterrupts.SerialRecieve; + return interrupt; + } + + public virtual byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0xB1: + /* REG_SER_DATA */ + retVal = serialData; + rxFull = false; + break; + + case 0xB3: + /* REG_SER_STATUS */ + ChangeBit(ref retVal, 7, enable); + ChangeBit(ref retVal, 6, baudRateSelect); + ChangeBit(ref retVal, 2, txEmpty); + ChangeBit(ref retVal, 1, rxOverrun); + ChangeBit(ref retVal, 0, rxFull); + break; + } + + return retVal; + } + + public virtual void WritePort(ushort port, byte value) + { + switch (port) + { + case 0xB1: + /* REG_SER_DATA */ + if (txEmpty) + { + serialData = value; + txEmpty = false; + } + break; + + case 0xB3: + /* REG_SER_STATUS */ + enable = IsBitSet(value, 7); + baudRateSelect = IsBitSet(value, 6); + rxOverrun = !IsBitSet(value, 5); + break; + } + } + + [Port("REG_SER_DATA", 0x0B1)] + [BitDescription("Serial data")] + [Format("X2")] + public byte SerialData => serialData; + [Port("REG_SER_STATUS", 0x0B3)] + [BitDescription("Serial enabled?", 7)] + public bool Enable => enable; + [Port("REG_SER_STATUS", 0x0B3)] + [BitDescription("Baud rate; is 38400 baud?", 6)] + public bool BaudRateSelect => baudRateSelect; + [Port("REG_SER_STATUS", 0x0B3)] + [BitDescription("TX empty?", 2)] + public bool TxEmpty => txEmpty; + [Port("REG_SER_STATUS", 0x0B3)] + [BitDescription("RX overrun?", 1)] + public bool RxOverrun => rxOverrun; + [Port("REG_SER_STATUS", 0x0B3)] + [BitDescription("RX full?", 0)] + public bool RxFull => rxFull; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs.meta new file mode 100644 index 0000000..a993eb3 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Serial/SerialPort.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c946ee9cecab7f343b5e8896d2d98d7a \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound.meta new file mode 100644 index 0000000..e081fa8 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f7258409b0150f847b07fd6219501ad8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs new file mode 100644 index 0000000..42cdf16 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs @@ -0,0 +1,126 @@ +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Interfaces; + +namespace StoicGoose.Core.Sound +{ + public class AswanSoundController : SoundControllerCommon + { + public override byte MaxMasterVolume => 2; + public override int NumChannels => 4; + + /* REG_SND_9697 */ + protected ushort unknown9697; + /* REG_SND_9899 */ + protected ushort unknown9899; + + public AswanSoundController(IMachine machine, int rate, int outChannels) : base(machine, rate, outChannels) { } + + public override void ResetRegisters() + { + base.ResetRegisters(); + + unknown9697 = 0; + unknown9899 = 0; + } + + public override int[] GenerateSample() + { + channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputRight & 0x07FF) << 5 : 0)); + + var mixedLeft = 0; + if (channel1.IsEnabled) mixedLeft += channel1.OutputLeft; + if (channel2.IsEnabled) mixedLeft += channel2.OutputLeft; + if (channel3.IsEnabled) mixedLeft += channel3.OutputLeft; + if (channel4.IsEnabled) mixedLeft += channel4.OutputLeft; + mixedLeft = (mixedLeft & 0x07FF) << 5; + + var mixedRight = 0; + if (channel1.IsEnabled) mixedRight += channel1.OutputRight; + if (channel2.IsEnabled) mixedRight += channel2.OutputRight; + if (channel3.IsEnabled) mixedRight += channel3.OutputRight; + if (channel4.IsEnabled) mixedRight += channel4.OutputRight; + mixedRight = (mixedRight & 0x07FF) << 5; + + return new[] { mixedLeft, mixedRight }; + } + + public override byte ReadPort(ushort port) + { + return port switch + { + /* REG_SND_9697 (low) */ + 0x96 => (byte)((unknown9697 >> 0) & 0b11111111), + /* REG_SND_9697 (high) */ + 0x97 => (byte)((unknown9697 >> 8) & 0b00000011), + /* REG_SND_9899 (low) */ + 0x98 => (byte)((unknown9899 >> 0) & 0b11111111), + /* REG_SND_9899 (high) */ + 0x99 => (byte)((unknown9899 >> 8) & 0b00000011), + /* REG_SND_9A */ + 0x9A => 0b111, + /* REG_SND_9B */ + 0x9B => 0b11111110, + /* REG_SND_9C */ + 0x9C => 0b11111111, + /* REG_SND_9D */ + 0x9D => 0b11111111, + /* Fall through to common */ + _ => base.ReadPort(port) + }; + } + + public override void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x96: + /* REG_SND_9697 (low) */ + unknown9697 = (ushort)((unknown9697 & 0x0300) | (value << 0)); + break; + + case 0x97: + /* REG_SND_9697 (high) */ + unknown9697 = (ushort)((unknown9697 & 0x00FF) | (value << 8)); + break; + + case 0x98: + /* REG_SND_9899 (low) */ + unknown9899 = (ushort)((unknown9899 & 0x0300) | (value << 0)); + break; + + case 0x99: + /* REG_SND_9899 (high) */ + unknown9899 = (ushort)((unknown9899 & 0x00FF) | (value << 8)); + break; + + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + /* REG_SND_9x */ + break; + + default: + /* Fall through to common */ + base.WritePort(port, value); + break; + } + } + + [Port("REG_SND_9697", 0x096, 0x097)] + [BitDescription("Unknown data", 0, 9)] + [Format("X4")] + public ushort Unknown9697 => unknown9697; + [Port("REG_SND_9899", 0x098, 0x099)] + [BitDescription("Unknown data", 0, 9)] + [Format("X4")] + public ushort Unknown9899 => unknown9899; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs.meta new file mode 100644 index 0000000..60fbf46 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/AswanSoundController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 28765af694138b54d82c34169449c831 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs new file mode 100644 index 0000000..c620925 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs @@ -0,0 +1,55 @@ +namespace StoicGoose.Core.Sound +{ + /* Channel 1, no additional features */ + public sealed class SoundChannel1 + { + const int counterReload = 2048; + + ushort counter; + byte pointer; + + public byte OutputLeft { get; set; } + public byte OutputRight { get; set; } + + readonly WaveTableReadDelegate waveTableReadDelegate; + + /* REG_SND_CH1_PITCH */ + public ushort Pitch { get; set; } + /* REG_SND_CH1_VOL */ + public byte VolumeLeft { get; set; } + public byte VolumeRight { get; set; } + /* REG_SND_CTRL */ + public bool IsEnabled { get; set; } + + public SoundChannel1(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead; + + public void Reset() + { + counter = counterReload; + pointer = 0; + OutputLeft = OutputRight = 0; + + Pitch = 0; + VolumeLeft = VolumeRight = 0; + IsEnabled = false; + } + + public void Step() + { + counter--; + if (counter == Pitch) + { + var data = waveTableReadDelegate((ushort)(pointer >> 1)); + if ((pointer & 0b1) == 0b1) data >>= 4; + data &= 0x0F; + + OutputLeft = (byte)(data * VolumeLeft); + OutputRight = (byte)(data * VolumeRight); + + pointer++; + pointer &= 0b11111; + counter = counterReload; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs.meta new file mode 100644 index 0000000..accfd79 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel1.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 72cd30fc769465c4e8a91b33b4baf47d \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs new file mode 100644 index 0000000..b2d9f97 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs @@ -0,0 +1,75 @@ +namespace StoicGoose.Core.Sound +{ + /* Channel 2, supports PCM voice */ + public sealed class SoundChannel2 + { + const int counterReload = 2048; + + ushort counter; + byte pointer; + + public byte OutputLeft { get; set; } + public byte OutputRight { get; set; } + + readonly WaveTableReadDelegate waveTableReadDelegate; + + /* REG_SND_CH2_PITCH */ + public ushort Pitch { get; set; } + /* REG_SND_CH2_VOL */ + public byte VolumeLeft { get; set; } + public byte VolumeRight { get; set; } + /* REG_SND_CTRL */ + public bool IsEnabled { get; set; } + public bool IsVoiceEnabled { get; set; } + + /* REG_SND_VOICE_CTRL */ + public bool PcmRightFull { get; set; } + public bool PcmRightHalf { get; set; } + public bool PcmLeftFull { get; set; } + public bool PcmLeftHalf { get; set; } + + public SoundChannel2(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead; + + public void Reset() + { + counter = counterReload; + pointer = 0; + OutputLeft = OutputRight = 0; + + Pitch = 0; + VolumeLeft = VolumeRight = 0; + IsEnabled = false; + + IsVoiceEnabled = false; + + PcmRightFull = PcmRightHalf = PcmLeftFull = PcmLeftHalf = false; + } + + public void Step() + { + if (IsVoiceEnabled) + { + var pcm = (ushort)(VolumeLeft << 4 | VolumeRight); + OutputLeft = (byte)(PcmLeftFull ? pcm : (PcmLeftHalf ? pcm >> 1 : 0)); + OutputRight = (byte)(PcmRightFull ? pcm : (PcmRightHalf ? pcm >> 1 : 0)); + } + else + { + counter--; + if (counter == Pitch) + { + var data = waveTableReadDelegate((ushort)(pointer >> 1)); + if ((pointer & 0b1) == 0b1) data >>= 4; + data &= 0x0F; + + OutputLeft = (byte)(data * VolumeLeft); + OutputRight = (byte)(data * VolumeRight); + + pointer++; + pointer &= 0b11111; + counter = counterReload; + } + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs.meta new file mode 100644 index 0000000..82a1d81 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel2.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4082002c536d05c4f97e428bfdfbb686 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs new file mode 100644 index 0000000..5c6b88a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs @@ -0,0 +1,88 @@ +namespace StoicGoose.Core.Sound +{ + /* Channel 3, has optional sweep */ + public sealed class SoundChannel3 + { + const int counterReload = 2048; + const int sweepReload = 32 * 256; + + ushort counter; + byte pointer; + + public byte OutputLeft { get; set; } + public byte OutputRight { get; set; } + + int sweepCounter; + int sweepCycles; + + readonly WaveTableReadDelegate waveTableReadDelegate; + + /* REG_SND_CH3_PITCH */ + public ushort Pitch { get; set; } + /* REG_SND_CH3_VOL */ + public byte VolumeLeft { get; set; } + public byte VolumeRight { get; set; } + /* REG_SND_CTRL */ + public bool IsEnabled { get; set; } + public bool IsSweepEnabled { get; set; } + + /* REG_SND_SWEEP_VALUE */ + public sbyte SweepValue { get; set; } + /* REG_SND_SWEEP_TIME */ + public byte SweepTime { get; set; } + + public SoundChannel3(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead; + + public void Reset() + { + counter = counterReload; + pointer = 0; + OutputLeft = OutputRight = 0; + + Pitch = 0; + VolumeLeft = VolumeRight = 0; + IsEnabled = false; + + IsSweepEnabled = false; + + sweepCounter = 0; + sweepCycles = sweepReload; + + SweepValue = 0; + SweepTime = 0; + } + + public void Step() + { + if (IsSweepEnabled) + { + sweepCycles--; + if (sweepCycles == 0) + { + sweepCounter--; + if (sweepCounter <= 0) + { + sweepCounter = SweepTime; + Pitch = (ushort)(Pitch + SweepValue); + } + } + sweepCycles = sweepReload; + } + + counter--; + if (counter == Pitch) + { + var data = waveTableReadDelegate((ushort)(pointer >> 1)); + if ((pointer & 0b1) == 0b1) data >>= 4; + data &= 0x0F; + + OutputLeft = (byte)(data * VolumeLeft); + OutputRight = (byte)(data * VolumeRight); + + pointer++; + pointer &= 0b11111; + counter = counterReload; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs.meta new file mode 100644 index 0000000..4ba8af6 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel3.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2885470480fbb3846b82cc3aec9dc315 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs new file mode 100644 index 0000000..755ebbd --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs @@ -0,0 +1,88 @@ +namespace StoicGoose.Core.Sound +{ + /* Channel 4, supports noise */ + public sealed class SoundChannel4 + { + const int counterReload = 2048; + + readonly static byte[] noiseLfsrTaps = { 14, 10, 13, 4, 8, 6, 9, 11 }; + + ushort counter; + byte pointer; + + public byte OutputLeft { get; set; } + public byte OutputRight { get; set; } + + readonly WaveTableReadDelegate waveTableReadDelegate; + + /* REG_SND_CH4_PITCH */ + public ushort Pitch { get; set; } + /* REG_SND_CH4_VOL */ + public byte VolumeLeft { get; set; } + public byte VolumeRight { get; set; } + /* REG_SND_CTRL */ + public bool IsEnabled { get; set; } + public bool IsNoiseEnabled { get; set; } + + /* REG_SND_NOISE */ + public byte NoiseMode { get; set; } + public bool NoiseReset { get; set; } + public bool NoiseEnable { get; set; } + /* REG_SND_RANDOM */ + public ushort NoiseLfsr { get; set; } + + public SoundChannel4(WaveTableReadDelegate waveTableRead) => waveTableReadDelegate = waveTableRead; + + public void Reset() + { + counter = counterReload; + pointer = 0; + OutputLeft = OutputRight = 0; + + Pitch = 0; + VolumeLeft = VolumeRight = 0; + IsEnabled = false; + + IsNoiseEnabled = false; + + NoiseMode = 0; + NoiseReset = NoiseEnable = false; + NoiseLfsr = 0; + } + + public void Step() + { + counter--; + if (counter == Pitch) + { + if (NoiseEnable) + { + var tap = noiseLfsrTaps[NoiseMode]; + var noise = (1 ^ (NoiseLfsr >> 7) ^ (NoiseLfsr >> tap)) & 0b1; + NoiseLfsr = (ushort)(((NoiseLfsr << 1) | noise) & 0x7FFF); + } + + var data = IsNoiseEnabled ? ((NoiseLfsr & 0b1) * 0x0F) : waveTableReadDelegate((ushort)(pointer >> 1)); + if (!IsNoiseEnabled) + { + if ((pointer & 0b1) == 0b1) data >>= 4; + data &= 0x0F; + } + + OutputLeft = (byte)(data * VolumeLeft); + OutputRight = (byte)(data * VolumeRight); + + if (NoiseReset) + { + NoiseLfsr = 0; + OutputLeft = OutputRight = 0; + NoiseReset = false; + } + + pointer++; + pointer &= 0b11111; + counter = counterReload; + } + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs.meta new file mode 100644 index 0000000..fb9f58c --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannel4.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b6fec75dc93d8b646a1294310530ae97 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs new file mode 100644 index 0000000..b27cae5 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs @@ -0,0 +1,55 @@ +namespace StoicGoose.Core.Sound +{ + /* HyperVoice channel */ + public sealed class SoundChannelHyperVoice + { + public byte OutputLeft { get; set; } + public byte OutputRight { get; set; } + + /* REG_HYPER_CTRL */ + public bool IsEnabled { get; set; } + public int ScalingMode { get; set; } + public int Volume { get; set; } + public byte CtrlUnknown { get; set; } + + /* REG_HYPER_CHAN_CTRL */ + public bool RightEnable { get; set; } + public bool LeftEnable { get; set; } + public byte ChanCtrlUnknown { get; set; } + + /* REG_SND_HYPERVOICE */ + public byte Data { get; set; } + + public SoundChannelHyperVoice() { } + + public void Reset() + { + OutputLeft = OutputRight = 0; + + IsEnabled = false; + ScalingMode = Volume = 0; + CtrlUnknown = 0; + + RightEnable = LeftEnable = false; + ChanCtrlUnknown = 0; + + Data = 0; + } + + public void Step() + { + var output = (byte)0; + + switch (ScalingMode) + { + case 0: output = (byte)(Data << 3 - Volume); break; + case 1: output = (byte)((Data << 3 - Volume) | (-0x100 << 3 - Volume)); break; + case 2: output = (byte)(Data << 3 - Volume); break; // ??? + case 3: output = (byte)(Data << 3); break; + } + + OutputLeft = LeftEnable ? output : (byte)0; + OutputRight = RightEnable ? output : (byte)0; + } + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs.meta new file mode 100644 index 0000000..b93bb62 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundChannelHyperVoice.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b15fb27a01956c340b331a6969e590f9 \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs new file mode 100644 index 0000000..70c3057 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs @@ -0,0 +1,487 @@ +using System; +using System.Collections.Generic; + +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Interfaces; +using StoicGoose.Core.Machines; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Sound +{ + public delegate byte WaveTableReadDelegate(ushort address); + + public abstract partial class SoundControllerCommon : IPortAccessComponent + { + /* http://daifukkat.su/docs/wsman/#hw_sound */ + + public abstract byte MaxMasterVolume { get; } + public abstract int NumChannels { get; } + + readonly int sampleRate, numOutputChannels; + + protected readonly SoundChannel1 channel1 = default; + protected readonly SoundChannel2 channel2 = default; + protected readonly SoundChannel3 channel3 = default; + protected readonly SoundChannel4 channel4 = default; + + protected readonly List[] channelSampleBuffers = default; + protected readonly List mixedSampleBuffer = new(); + + public short[][] LastEnqueuedChannelSamples { get; private set; } = default; + public short[] LastEnqueuedMixedSamples { get; private set; } = Array.Empty(); + + public Action SendSamples { get; set; } = default; + + readonly double clockRate, refreshRate; + readonly int samplesPerFrame, cyclesPerFrame, cyclesPerSample; + int cycleCount; + + protected readonly IMachine machine = default; + + /* REG_SND_WAVE_BASE */ + protected byte waveTableBase; + /* REG_SND_OUTPUT */ + protected bool speakerEnable, headphoneEnable, headphonesConnected; + protected byte speakerVolumeShift; + /* REG_SND_VOLUME */ + protected byte masterVolume; + + public SoundControllerCommon(IMachine machine, int rate, int outChannels) + { + this.machine = machine; + + sampleRate = rate; + numOutputChannels = outChannels; + + channel1 = new SoundChannel1((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (0 << 4) + a))); + channel2 = new SoundChannel2((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (1 << 4) + a))); + channel3 = new SoundChannel3((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (2 << 4) + a))); + channel4 = new SoundChannel4((a) => this.machine.ReadMemory((uint)((waveTableBase << 6) + (3 << 4) + a))); + + channelSampleBuffers = new List[NumChannels]; + for (var i = 0; i < channelSampleBuffers.Length; i++) channelSampleBuffers[i] = new(); + + LastEnqueuedChannelSamples = new short[NumChannels][]; + + clockRate = MachineCommon.CpuClock; + refreshRate = Display.DisplayControllerCommon.VerticalClock; + + samplesPerFrame = (int)(sampleRate / refreshRate); + cyclesPerFrame = (int)(clockRate / refreshRate); + cyclesPerSample = cyclesPerFrame / samplesPerFrame; + } + + public virtual void Reset() + { + cycleCount = 0; + + channel1.Reset(); + channel2.Reset(); + channel3.Reset(); + channel4.Reset(); + + FlushSamples(); + + ResetRegisters(); + } + + public virtual void ResetRegisters() + { + waveTableBase = 0; + speakerEnable = headphoneEnable = false; + headphonesConnected = true; /* NOTE: always set for stereo sound */ + speakerVolumeShift = 0; + masterVolume = MaxMasterVolume; + } + + public void Shutdown() + { + /* Nothing to do */ + } + + public void ChangeMasterVolume() + { + var newMasterVolume = MasterVolume - 1; + if (newMasterVolume < 0) newMasterVolume = MaxMasterVolume; + else if (newMasterVolume > MaxMasterVolume) newMasterVolume = 0; + + masterVolume = (byte)newMasterVolume; + } + + public void Step(int clockCyclesInStep) + { + cycleCount += clockCyclesInStep; + + for (int i = 0; i < clockCyclesInStep; i++) + StepChannels(); + + if (cycleCount >= cyclesPerSample) + { + ProcessSample(GenerateSample()); + cycleCount -= cyclesPerSample; + } + + if (mixedSampleBuffer.Count >= (samplesPerFrame * numOutputChannels)) + { + var sampleArray = mixedSampleBuffer.ToArray(); + + LastEnqueuedMixedSamples = sampleArray; + for (var i = 0; i < NumChannels; i++) LastEnqueuedChannelSamples[i] = channelSampleBuffers[i].ToArray(); + + SendSamples?.Invoke(sampleArray.Clone() as short[]); + + FlushSamples(); + } + } + + public virtual void StepChannels() + { + channel1.Step(); + channel2.Step(); + channel3.Step(); + channel4.Step(); + } + + public abstract int[] GenerateSample(); + + public virtual void ProcessSample(int[] lrSamples) + { + if (headphonesConnected && !headphoneEnable && !speakerEnable) + /* Headphones connected but neither headphones nor speaker enabled? Don't output sound */ + lrSamples[0] = lrSamples[1] = 0; + else if (!headphonesConnected) + /* Otherwise, no headphones connected? Mix down to mono, perform volume shift */ + lrSamples[0] = lrSamples[1] = ((lrSamples[0] + lrSamples[1]) / 2) >> speakerVolumeShift; + + mixedSampleBuffer.Add((short)(lrSamples[0] * (masterVolume / (double)MaxMasterVolume))); /* Left */ + mixedSampleBuffer.Add((short)(lrSamples[1] * (masterVolume / (double)MaxMasterVolume))); /* Right */ + } + + public void FlushSamples() + { + foreach (var buffer in channelSampleBuffers) + buffer.Clear(); + + mixedSampleBuffer.Clear(); + } + + public virtual byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x80: + case 0x81: + /* REG_SND_CH1_PITCH */ + retVal |= (byte)(channel1.Pitch >> ((port & 0b1) * 8)); + break; + case 0x82: + case 0x83: + /* REG_SND_CH2_PITCH */ + retVal |= (byte)(channel2.Pitch >> ((port & 0b1) * 8)); + break; + case 0x84: + case 0x85: + /* REG_SND_CH3_PITCH */ + retVal |= (byte)(channel3.Pitch >> ((port & 0b1) * 8)); + break; + case 0x86: + case 0x87: + /* REG_SND_CH4_PITCH */ + retVal |= (byte)(channel4.Pitch >> ((port & 0b1) * 8)); + break; + + case 0x88: + /* REG_SND_CH1_VOL */ + retVal |= (byte)(channel1.VolumeLeft << 4 | channel1.VolumeRight); + break; + case 0x89: + /* REG_SND_CH2_VOL */ + retVal |= (byte)(channel2.VolumeLeft << 4 | channel2.VolumeRight); + break; + case 0x8A: + /* REG_SND_CH3_VOL */ + retVal |= (byte)(channel3.VolumeLeft << 4 | channel3.VolumeRight); + break; + case 0x8B: + /* REG_SND_CH4_VOL */ + retVal |= (byte)(channel4.VolumeLeft << 4 | channel4.VolumeRight); + break; + + case 0x8C: + /* REG_SND_SWEEP_VALUE */ + retVal |= (byte)channel3.SweepValue; + break; + + case 0x8D: + /* REG_SND_SWEEP_TIME */ + retVal |= (byte)(channel3.SweepTime & 0b11111); + break; + + case 0x8E: + /* REG_SND_NOISE */ + retVal |= (byte)(channel4.NoiseMode & 0b111); + /* Noise reset (bit 3) always reads 0 */ + ChangeBit(ref retVal, 4, channel4.NoiseEnable); + break; + + case 0x8F: + /* REG_SND_WAVE_BASE */ + retVal |= waveTableBase; + break; + + case 0x90: + /* REG_SND_CTRL */ + ChangeBit(ref retVal, 0, channel1.IsEnabled); + ChangeBit(ref retVal, 1, channel2.IsEnabled); + ChangeBit(ref retVal, 2, channel3.IsEnabled); + ChangeBit(ref retVal, 3, channel4.IsEnabled); + ChangeBit(ref retVal, 5, channel2.IsVoiceEnabled); + ChangeBit(ref retVal, 6, channel3.IsSweepEnabled); + ChangeBit(ref retVal, 7, channel4.IsNoiseEnabled); + break; + + case 0x91: + /* REG_SND_OUTPUT */ + ChangeBit(ref retVal, 0, speakerEnable); + ChangeBit(ref retVal, 3, headphoneEnable); + ChangeBit(ref retVal, 7, headphonesConnected); + retVal |= (byte)((speakerVolumeShift & 0b11) << 1); + break; + + case 0x92: + case 0x93: + /* REG_SND_RANDOM */ + retVal |= (byte)((channel4.NoiseLfsr >> ((port & 0b1) * 8)) & 0xFF); + break; + + case 0x94: + /* REG_SND_VOICE_CTRL */ + ChangeBit(ref retVal, 0, channel2.PcmRightFull); + ChangeBit(ref retVal, 1, channel2.PcmRightHalf); + ChangeBit(ref retVal, 2, channel2.PcmLeftFull); + ChangeBit(ref retVal, 3, channel2.PcmLeftHalf); + break; + + case 0x9E: + /* REG_SND_VOLUME */ + retVal |= (byte)(masterVolume & 0b11); + break; + + default: + throw new NotImplementedException($"Unimplemented sound register read {port:X2}"); + } + + return retVal; + } + + public virtual void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x80: + case 0x81: + /* REG_SND_CH1_PITCH */ + channel1.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF); + channel1.Pitch |= (ushort)(value << ((port & 0b1) * 8)); + break; + case 0x82: + case 0x83: + /* REG_SND_CH2_PITCH */ + channel2.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF); + channel2.Pitch |= (ushort)(value << ((port & 0b1) * 8)); + break; + case 0x84: + case 0x85: + /* REG_SND_CH3_PITCH */ + channel3.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF); + channel3.Pitch |= (ushort)(value << ((port & 0b1) * 8)); + break; + case 0x86: + case 0x87: + /* REG_SND_CH4_PITCH */ + channel4.Pitch &= (ushort)((port & 0b1) != 0b1 ? 0x0700 : 0x00FF); + channel4.Pitch |= (ushort)(value << ((port & 0b1) * 8)); + break; + + case 0x88: + /* REG_SND_CH1_VOL */ + channel1.VolumeLeft = (byte)((value >> 4) & 0b1111); + channel1.VolumeRight = (byte)((value >> 0) & 0b1111); + break; + case 0x89: + /* REG_SND_CH2_VOL */ + channel2.VolumeLeft = (byte)((value >> 4) & 0b1111); + channel2.VolumeRight = (byte)((value >> 0) & 0b1111); + break; + case 0x8A: + /* REG_SND_CH3_VOL */ + channel3.VolumeLeft = (byte)((value >> 4) & 0b1111); + channel3.VolumeRight = (byte)((value >> 0) & 0b1111); + break; + case 0x8B: + /* REG_SND_CH4_VOL */ + channel4.VolumeLeft = (byte)((value >> 4) & 0b1111); + channel4.VolumeRight = (byte)((value >> 0) & 0b1111); + break; + + case 0x8C: + /* REG_SND_SWEEP_VALUE */ + channel3.SweepValue = (sbyte)value; + break; + + case 0x8D: + /* REG_SND_SWEEP_TIME */ + channel3.SweepTime = (byte)(value & 0b11111); + break; + + case 0x8E: + /* REG_SND_NOISE */ + channel4.NoiseMode = (byte)(value & 0b111); + channel4.NoiseReset = IsBitSet(value, 3); + channel4.NoiseEnable = IsBitSet(value, 4); + break; + + case 0x8F: + /* REG_SND_WAVE_BASE */ + waveTableBase = value; + break; + + case 0x90: + /* REG_SND_CTRL */ + channel1.IsEnabled = IsBitSet(value, 0); + channel2.IsEnabled = IsBitSet(value, 1); + channel3.IsEnabled = IsBitSet(value, 2); + channel4.IsEnabled = IsBitSet(value, 3); + channel2.IsVoiceEnabled = IsBitSet(value, 5); + channel3.IsSweepEnabled = IsBitSet(value, 6); + channel4.IsNoiseEnabled = IsBitSet(value, 7); + break; + + case 0x91: + /* REG_SND_OUTPUT */ + speakerEnable = IsBitSet(value, 0); + speakerVolumeShift = (byte)((value >> 1) & 0b11); + headphoneEnable = IsBitSet(value, 3); + /* Headphones connected (bit 7) is read-only */ + break; + + case 0x92: + case 0x93: + /* REG_SND_RANDOM */ + break; + + case 0x94: + /* REG_SND_VOICE_CTRL */ + channel2.PcmRightFull = IsBitSet(value, 0); + channel2.PcmRightHalf = IsBitSet(value, 1); + channel2.PcmLeftFull = IsBitSet(value, 2); + channel2.PcmLeftHalf = IsBitSet(value, 3); + break; + + case 0x9E: + /* REG_SND_VOLUME */ + masterVolume = (byte)(value & 0b11); + break; + + default: + throw new NotImplementedException($"Unimplemented sound register write {port:X2}"); + } + } + + [Port("REG_SND_CH1_PITCH", 0x080, 0x081)] + [BitDescription("Channel 1 pitch (frequency reload)", 0, 10)] + public ushort Channel1Pitch => channel1.Pitch; + [Port("REG_SND_CH2_PITCH", 0x082, 0x083)] + [BitDescription("Channel 2 pitch (frequency reload)", 0, 10)] + public ushort Channel2Pitch => channel2.Pitch; + [Port("REG_SND_CH3_PITCH", 0x084, 0x085)] + [BitDescription("Channel 3 pitch (frequency reload)", 0, 10)] + public ushort Channel3Pitch => channel3.Pitch; + [Port("REG_SND_CH4_PITCH", 0x086, 0x087)] + [BitDescription("Channel 4 pitch (frequency reload)", 0, 10)] + public ushort Channel4Pitch => channel4.Pitch; + [Port("REG_SND_CH1_VOL", 0x088)] + [BitDescription("Channel 1 volume right", 0, 3)] + public byte Channel1VolumeRight => channel1.VolumeRight; + [Port("REG_SND_CH1_VOL", 0x088)] + [BitDescription("Channel 1 volume left", 4, 7)] + public byte Channel1VolumeLeft => channel1.VolumeLeft; + [Port("REG_SND_CH2_VOL", 0x089)] + [BitDescription("Channel 2 volume right", 0, 3)] + public byte Channel2VolumeRight => channel2.VolumeRight; + [Port("REG_SND_CH2_VOL", 0x089)] + [BitDescription("Channel 2 volume left", 4, 7)] + public byte Channel2VolumeLeft => channel2.VolumeLeft; + [Port("REG_SND_CH3_VOL", 0x08A)] + [BitDescription("Channel 3 volume right", 0, 3)] + public byte Channel3VolumeRight => channel3.VolumeRight; + [Port("REG_SND_CH3_VOL", 0x08A)] + [BitDescription("Channel 3 volume left", 4, 7)] + public byte Channel3VolumeLeft => channel3.VolumeLeft; + [Port("REG_SND_CH4_VOL", 0x08B)] + [BitDescription("Channel 4 volume right", 0, 3)] + public byte Channel4VolumeRight => channel4.VolumeRight; + [Port("REG_SND_CH4_VOL", 0x08B)] + [BitDescription("Channel 4 volume left", 4, 7)] + public byte Channel4VolumeLeft => channel4.VolumeLeft; + [Port("REG_SND_SWEEP_VALUE", 0x08C)] + [BitDescription("Channel 3 sweep value")] + public sbyte Channel3SweepValue => channel3.SweepValue; + [Port("REG_SND_SWEEP_TIME", 0x08D)] + [BitDescription("Channel 3 sweep time", 0, 4)] + public byte Channel3SweepTime => channel3.SweepTime; + [Port("REG_SND_NOISE", 0x08E)] + [BitDescription("Channel 4 noise mode", 0, 2)] + public byte Channel4NoiseMode => channel4.NoiseMode; + [Port("REG_SND_NOISE", 0x08E)] + [BitDescription("Is channel 4 noise enabled?", 4)] + public bool Channel4NoiseEnable => channel4.NoiseEnable; + [Port("REG_SND_WAVE_BASE", 0x08F)] + [BitDescription("Wavetable base address")] + [Format("X4", 6)] + public byte WaveTableBase => waveTableBase; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 1 enabled?", 0)] + public bool Channel1IsEnabled => channel1.IsEnabled; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 2 enabled?", 1)] + public bool Channel2IsEnabled => channel2.IsEnabled; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 3 enabled?", 2)] + public bool Channel3IsEnabled => channel3.IsEnabled; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 4 enabled?", 3)] + public bool Channel4IsEnabled => channel4.IsEnabled; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 2 in voice mode?", 5)] + public bool Channel2IsVoiceEnabled => channel2.IsVoiceEnabled; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 3 in sweep mode?", 6)] + public bool Channel3IsSweepEnabled => channel3.IsSweepEnabled; + [Port("REG_SND_CTRL", 0x090)] + [BitDescription("Is channel 4 in noise mode?", 7)] + public bool Channel4IsNoiseEnabled => channel4.IsNoiseEnabled; + [Port("REG_SND_OUTPUT", 0x091)] + [BitDescription("Is speaker enabled?", 0)] + public bool SpeakerEnable => speakerEnable; + [Port("REG_SND_OUTPUT", 0x091)] + [BitDescription("Speaker PWM volume bitshift", 1, 2)] + public byte SpeakerVolumeShift => speakerVolumeShift; + [Port("REG_SND_OUTPUT", 0x091)] + [BitDescription("Are headphones enabled?", 3)] + public bool HeadphoneEnable => headphoneEnable; + [Port("REG_SND_OUTPUT", 0x091)] + [BitDescription("Are headphones connected?", 7)] + public bool HeadphonesConnected => headphonesConnected; + [Port("REG_SND_RANDOM", 0x092, 0x093)] + [BitDescription("Current noise LFSR value", 0, 14)] + [Format("X4")] + public ushort Channel4NoiseLfsr => channel4.NoiseLfsr; + [Port("REG_SND_VOLUME", 0x09E)] + [BitDescription("Master volume level", 0, 1)] + public byte MasterVolume => masterVolume; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs.meta new file mode 100644 index 0000000..935f95a --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SoundControllerCommon.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 58b2556218f34ae4eaca2861c63517cd \ No newline at end of file diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs new file mode 100644 index 0000000..4922a42 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs @@ -0,0 +1,182 @@ +using StoicGoose.Common.Attributes; +using StoicGoose.Core.Interfaces; + +using static StoicGoose.Common.Utilities.BitHandling; + +namespace StoicGoose.Core.Sound +{ + public class SphinxSoundController : SoundControllerCommon + { + public override byte MaxMasterVolume => 3; + public override int NumChannels => 5; + + readonly SoundChannelHyperVoice channelHyperVoice = default; + + public SphinxSoundController(IMachine machine, int rate, int outChannels) : base(machine, rate, outChannels) + { + channelHyperVoice = new(); + } + + public override void Reset() + { + base.Reset(); + + channelHyperVoice.Reset(); + } + + public override void StepChannels() + { + base.StepChannels(); + + channelHyperVoice.Step(); + } + + public override int[] GenerateSample() + { + channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[0].Add((short)(channel1.IsEnabled ? (channel1.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[1].Add((short)(channel2.IsEnabled ? (channel2.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[2].Add((short)(channel3.IsEnabled ? (channel3.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[3].Add((short)(channel4.IsEnabled ? (channel4.OutputRight & 0x07FF) << 5 : 0)); + channelSampleBuffers[4].Add((short)(channelHyperVoice.IsEnabled ? (channelHyperVoice.OutputLeft & 0x07FF) << 5 : 0)); + channelSampleBuffers[4].Add((short)(channelHyperVoice.IsEnabled ? (channelHyperVoice.OutputRight & 0x07FF) << 5 : 0)); + + var mixedLeft = 0; + if (channel1.IsEnabled) mixedLeft += channel1.OutputLeft; + if (channel2.IsEnabled) mixedLeft += channel2.OutputLeft; + if (channel3.IsEnabled) mixedLeft += channel3.OutputLeft; + if (channel4.IsEnabled) mixedLeft += channel4.OutputLeft; + if (channelHyperVoice.IsEnabled && headphonesConnected) mixedLeft += channelHyperVoice.OutputLeft; + mixedLeft = (mixedLeft & 0x07FF) << 5; + + var mixedRight = 0; + if (channel1.IsEnabled) mixedRight += channel1.OutputRight; + if (channel2.IsEnabled) mixedRight += channel2.OutputRight; + if (channel3.IsEnabled) mixedRight += channel3.OutputRight; + if (channel4.IsEnabled) mixedRight += channel4.OutputRight; + if (channelHyperVoice.IsEnabled && headphonesConnected) mixedRight += channelHyperVoice.OutputRight; + mixedRight = (mixedRight & 0x07FF) << 5; + + return new[] { mixedLeft, mixedRight }; + } + + public override byte ReadPort(ushort port) + { + var retVal = (byte)0; + + switch (port) + { + case 0x6A: + /* REG_HYPER_CTRL */ + ChangeBit(ref retVal, 7, channelHyperVoice.IsEnabled); + retVal |= (byte)((channelHyperVoice.CtrlUnknown << 4) & 0b111); + retVal |= (byte)((channelHyperVoice.ScalingMode << 2) & 0b11); + retVal |= (byte)((channelHyperVoice.Volume << 0) & 0b11); + break; + + case 0x6B: + /* REG_HYPER_CHAN_CTRL */ + ChangeBit(ref retVal, 6, channelHyperVoice.RightEnable); + ChangeBit(ref retVal, 5, channelHyperVoice.LeftEnable); + retVal |= (byte)((channelHyperVoice.ChanCtrlUnknown << 0) & 0b1111); + break; + + case 0x95: + /* REG_SND_HYPERVOICE */ + retVal |= channelHyperVoice.Data; + break; + + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + /* REG_SND_9x */ + retVal = 0; + break; + + default: + /* Fall through to common */ + retVal |= base.ReadPort(port); + break; + } + + return retVal; + } + + public override void WritePort(ushort port, byte value) + { + switch (port) + { + case 0x6A: + /* REG_HYPER_CTRL */ + channelHyperVoice.IsEnabled = IsBitSet(value, 7); + channelHyperVoice.CtrlUnknown = (byte)((value >> 4) & 0b111); + channelHyperVoice.ScalingMode = (byte)((value >> 2) & 0b11); + channelHyperVoice.Volume = (byte)((value >> 0) & 0b11); + break; + + case 0x6B: + /* REG_HYPER_CHAN_CTRL */ + channelHyperVoice.RightEnable = IsBitSet(value, 6); + channelHyperVoice.LeftEnable = IsBitSet(value, 5); + channelHyperVoice.ChanCtrlUnknown = (byte)((value >> 0) & 0b1111); + break; + + case 0x95: + /* REG_SND_HYPERVOICE */ + channelHyperVoice.Data = value; + break; + + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + /* REG_SND_9x */ + break; + + default: + /* Fall through to common */ + base.WritePort(port, value); + break; + } + } + + [Port("REG_HYPER_CTRL", 0x06A)] + [BitDescription("Is HyperVoice enabled?", 7)] + public bool ChannelHyperVoiceIsEnable => channelHyperVoice.IsEnabled; + [Port("REG_HYPER_CTRL", 0x06A)] + [BitDescription("HyperVoice control unknown", 4, 6)] + public byte ChannelHyperVoiceCtrlUnknown => channelHyperVoice.CtrlUnknown; + [Port("REG_HYPER_CTRL", 0x06A)] + [BitDescription("HyperVoice scaling mode", 2, 3)] + public int ChannelHyperVoiceScalingMode => channelHyperVoice.ScalingMode; + [Port("REG_HYPER_CTRL", 0x06A)] + [BitDescription("HyperVoice volume", 0, 1)] + public int ChannelHyperVoiceVolume => channelHyperVoice.Volume; + + [Port("REG_HYPER_CHAN_CTRL", 0x06B)] + [BitDescription("Is HyperVoice right channel enabled?", 6)] + public bool ChannelHyperVoiceChanRightEnable => channelHyperVoice.RightEnable; + [Port("REG_HYPER_CHAN_CTRL", 0x06B)] + [BitDescription("Is HyperVoice left channel enabled?", 5)] + public bool ChannelHyperVoiceChanLeftEnable => channelHyperVoice.LeftEnable; + [Port("REG_HYPER_CHAN_CTRL", 0x06B)] + [BitDescription("HyperVoice channel control unknown", 0, 3)] + public byte ChannelHyperVoiceChanCtrlUnknown => channelHyperVoice.ChanCtrlUnknown; + + [Port("REG_SND_HYPERVOICE", 0x095)] + [BitDescription("HyperVoice channel working sample")] + public byte ChannelHyperVoiceData => channelHyperVoice.Data; + } +} diff --git a/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs.meta b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs.meta new file mode 100644 index 0000000..0d38353 --- /dev/null +++ b/Assets/Plugins/StoicGooseUnity/StoicGoose.Core/Sound/SphinxSoundController.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f1a789d9d88897f498d2634d568514c3 \ No newline at end of file diff --git a/Assets/Readme.asset b/Assets/Readme.asset new file mode 100644 index 0000000..77c2f83 --- /dev/null +++ b/Assets/Readme.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fcf7219bab7fe46a1ad266029b2fee19, type: 3} + m_Name: Readme + m_EditorClassIdentifier: + icon: {fileID: 2800000, guid: 727a75301c3d24613a3ebcec4a24c2c8, type: 3} + title: URP Empty Template + sections: + - heading: Welcome to the Universal Render Pipeline + text: This template includes the settings and assets you need to start creating with the Universal Render Pipeline. + linkText: + url: + - heading: URP Documentation + text: + linkText: Read more about URP + url: https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest + - heading: Forums + text: + linkText: Get answers and support + url: https://forum.unity.com/forums/universal-render-pipeline.383/ + - heading: Report bugs + text: + linkText: Submit a report + url: https://unity3d.com/unity/qa/bug-reporting + loadedLayout: 1 diff --git a/Assets/Readme.asset.meta b/Assets/Readme.asset.meta new file mode 100644 index 0000000..ab3ad45 --- /dev/null +++ b/Assets/Readme.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8105016687592461f977c054a80ce2f2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes.meta b/Assets/Scenes.meta new file mode 100644 index 0000000..e59fb45 --- /dev/null +++ b/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9c53962885c2c4f449125a979d6ad240 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..ccd80d4 --- /dev/null +++ b/Assets/Scenes/SampleScene.unity @@ -0,0 +1,435 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &330585543 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 330585546} + - component: {fileID: 330585545} + - component: {fileID: 330585544} + - component: {fileID: 330585547} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &330585544 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 +--- !u!20 &330585545 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &330585546 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &330585547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 330585543} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_RenderShadows: 1 + m_RequiresDepthTextureOption: 2 + m_RequiresOpaqueTextureOption: 2 + m_CameraType: 0 + m_Cameras: [] + m_RendererIndex: -1 + m_VolumeLayerMask: + serializedVersion: 2 + m_Bits: 1 + m_VolumeTrigger: {fileID: 0} + m_VolumeFrameworkUpdateModeOption: 2 + m_RenderPostProcessing: 1 + m_Antialiasing: 0 + m_AntialiasingQuality: 2 + m_StopNaN: 0 + m_Dithering: 0 + m_ClearDepth: 1 + m_AllowXRRendering: 1 + m_AllowHDROutput: 1 + m_UseScreenCoordOverride: 0 + m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0} + m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0} + m_RequiresDepthTexture: 0 + m_RequiresColorTexture: 0 + m_Version: 2 + m_TaaSettings: + m_Quality: 3 + m_FrameInfluence: 0.1 + m_JitterScale: 1 + m_MipBias: 0 + m_VarianceClampScale: 0.9 + m_ContrastAdaptiveSharpening: 0 +--- !u!1 &410087039 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 410087041} + - component: {fileID: 410087040} + - component: {fileID: 410087042} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &410087040 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + m_Enabled: 1 + serializedVersion: 11 + m_Type: 1 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 2 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 5000 + m_UseColorTemperature: 1 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &410087041 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!114 &410087042 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 410087039} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Version: 3 + m_UsePipelineSettings: 1 + m_AdditionalLightsShadowResolutionTier: 2 + m_LightLayerMask: 1 + m_RenderingLayers: 1 + m_CustomShadowLayers: 0 + m_ShadowLayerMask: 1 + m_ShadowRenderingLayers: 1 + m_LightCookieSize: {x: 1, y: 1} + m_LightCookieOffset: {x: 0, y: 0} + m_SoftShadowQuality: 1 +--- !u!1 &832575517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 832575519} + - component: {fileID: 832575518} + m_Layer: 0 + m_Name: Global Volume + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!114 &832575518 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 832575517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IsGlobal: 1 + priority: 0 + blendDistance: 0 + weight: 1 + sharedProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} +--- !u!4 &832575519 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 832575517} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 330585546} + - {fileID: 410087041} + - {fileID: 832575519} diff --git a/Assets/Scenes/SampleScene.unity.meta b/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..9531828 --- /dev/null +++ b/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99c9720ab356a0642a771bea13969a05 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings.meta b/Assets/Settings.meta new file mode 100644 index 0000000..39b94dd --- /dev/null +++ b/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 709f11a7f3c4041caa4ef136ea32d874 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/DefaultVolumeProfile.asset b/Assets/Settings/DefaultVolumeProfile.asset new file mode 100644 index 0000000..6fb1822 --- /dev/null +++ b/Assets/Settings/DefaultVolumeProfile.asset @@ -0,0 +1,982 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-9167874883656233139 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5485954d14dfb9a4c8ead8edb0ded5b1, type: 3} + m_Name: LiftGammaGain + m_EditorClassIdentifier: + active: 1 + lift: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + gamma: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + gain: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} +--- !u!114 &-8270506406425502121 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 70afe9e12c7a7ed47911bb608a23a8ff, type: 3} + m_Name: SplitToning + m_EditorClassIdentifier: + active: 1 + shadows: + m_OverrideState: 1 + m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1} + highlights: + m_OverrideState: 1 + m_Value: {r: 0.5, g: 0.5, b: 0.5, a: 1} + balance: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-8104416584915340131 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: CopyPasteTestComponent2 + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEditor.Rendering.Tests:VolumeComponentCopyPasteTests/CopyPasteTestComponent2 + active: 1 + p1: + m_OverrideState: 1 + m_Value: 0 + p2: + m_OverrideState: 1 + m_Value: 0 + p21: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-7750755424749557576 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 60f3b30c03e6ba64d9a27dc9dba8f28d, type: 3} + m_Name: OutlineVolumeComponent + m_EditorClassIdentifier: + active: 1 + Enabled: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-7743500325797982168 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ccf1aba9553839d41ae37dd52e9ebcce, type: 3} + m_Name: MotionBlur + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + quality: + m_OverrideState: 1 + m_Value: 0 + intensity: + m_OverrideState: 1 + m_Value: 0 + clamp: + m_OverrideState: 1 + m_Value: 0.05 +--- !u!114 &-7274224791359825572 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0fd9ee276a1023e439cf7a9c393195fa, type: 3} + m_Name: TestAnimationCurveVolumeComponent + m_EditorClassIdentifier: + active: 1 + testParameter: + m_OverrideState: 1 + m_Value: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.5 + value: 10 + inSlope: 0 + outSlope: 10 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 15 + inSlope: 10 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &-6335409530604852063 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 66f335fb1ffd8684294ad653bf1c7564, type: 3} + m_Name: ColorAdjustments + m_EditorClassIdentifier: + active: 1 + postExposure: + m_OverrideState: 1 + m_Value: 0 + contrast: + m_OverrideState: 1 + m_Value: 0 + colorFilter: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + hueShift: + m_OverrideState: 1 + m_Value: 0 + saturation: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-6288072647309666549 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 29fa0085f50d5e54f8144f766051a691, type: 3} + m_Name: FilmGrain + m_EditorClassIdentifier: + active: 1 + type: + m_OverrideState: 1 + m_Value: 0 + intensity: + m_OverrideState: 1 + m_Value: 0 + response: + m_OverrideState: 1 + m_Value: 0.8 + texture: + m_OverrideState: 1 + m_Value: {fileID: 0} +--- !u!114 &-5520245016509672950 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3} + m_Name: Tonemapping + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + neutralHDRRangeReductionMode: + m_OverrideState: 1 + m_Value: 2 + acesPreset: + m_OverrideState: 1 + m_Value: 3 + hueShiftAmount: + m_OverrideState: 1 + m_Value: 0 + detectPaperWhite: + m_OverrideState: 1 + m_Value: 0 + paperWhite: + m_OverrideState: 1 + m_Value: 300 + detectBrightnessLimits: + m_OverrideState: 1 + m_Value: 1 + minNits: + m_OverrideState: 1 + m_Value: 0.005 + maxNits: + m_OverrideState: 1 + m_Value: 1000 +--- !u!114 &-5360449096862653589 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: VolumeComponentSupportedEverywhere + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEngine.Rendering.Tests:VolumeComponentEditorSupportedOnTests/VolumeComponentSupportedEverywhere + active: 1 +--- !u!114 &-5139089513906902183 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5a00a63fdd6bd2a45ab1f2d869305ffd, type: 3} + m_Name: OasisFogVolumeComponent + m_EditorClassIdentifier: + active: 1 + Density: + m_OverrideState: 1 + m_Value: 0 + StartDistance: + m_OverrideState: 1 + m_Value: 0 + HeightRange: + m_OverrideState: 1 + m_Value: {x: 0, y: 50} + Tint: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + SunScatteringIntensity: + m_OverrideState: 1 + m_Value: 2 +--- !u!114 &-4463884970436517307 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fb60a22f311433c4c962b888d1393f88, type: 3} + m_Name: PaniniProjection + m_EditorClassIdentifier: + active: 1 + distance: + m_OverrideState: 1 + m_Value: 0 + cropToFit: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &-1410297666881709256 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6bd486065ce11414fa40e631affc4900, type: 3} + m_Name: ProbeVolumesOptions + m_EditorClassIdentifier: + active: 1 + normalBias: + m_OverrideState: 1 + m_Value: 0.33 + viewBias: + m_OverrideState: 1 + m_Value: 0 + scaleBiasWithMinProbeDistance: + m_OverrideState: 1 + m_Value: 0 + samplingNoise: + m_OverrideState: 1 + m_Value: 0.1 + animateSamplingNoise: + m_OverrideState: 1 + m_Value: 1 + leakReductionMode: + m_OverrideState: 1 + m_Value: 1 + minValidDotProductValue: + m_OverrideState: 1 + m_Value: 0.1 + occlusionOnlyReflectionNormalization: + m_OverrideState: 1 + m_Value: 1 + intensityMultiplier: + m_OverrideState: 1 + m_Value: 1 + skyOcclusionIntensityMultiplier: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &-1216621516061285780 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: + active: 1 + skipIterations: + m_OverrideState: 1 + m_Value: 1 + threshold: + m_OverrideState: 1 + m_Value: 0.9 + intensity: + m_OverrideState: 1 + m_Value: 0 + scatter: + m_OverrideState: 1 + m_Value: 0.7 + clamp: + m_OverrideState: 1 + m_Value: 65472 + tint: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + highQualityFiltering: + m_OverrideState: 1 + m_Value: 0 + downscale: + m_OverrideState: 1 + m_Value: 0 + maxIterations: + m_OverrideState: 1 + m_Value: 6 + dirtTexture: + m_OverrideState: 1 + m_Value: {fileID: 0} + dimension: 1 + dirtIntensity: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-1170528603972255243 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 221518ef91623a7438a71fef23660601, type: 3} + m_Name: WhiteBalance + m_EditorClassIdentifier: + active: 1 + temperature: + m_OverrideState: 1 + m_Value: 0 + tint: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &-581120513425526550 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: CopyPasteTestComponent3 + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEditor.Rendering.Tests:VolumeComponentCopyPasteTests/CopyPasteTestComponent3 + active: 1 + p1: + m_OverrideState: 1 + m_Value: 0 + p2: + m_OverrideState: 1 + m_Value: 0 + p31: + m_OverrideState: 1 + m_Value: {r: 0, g: 0, b: 0, a: 1} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} + m_Name: DefaultVolumeProfile + m_EditorClassIdentifier: + components: + - {fileID: -9167874883656233139} + - {fileID: 1918650496244738858} + - {fileID: 853819529557874667} + - {fileID: 1052315754049611418} + - {fileID: -1170528603972255243} + - {fileID: -8270506406425502121} + - {fileID: -5520245016509672950} + - {fileID: 7173750748008157695} + - {fileID: 1666464333004379222} + - {fileID: 9001657382290151224} + - {fileID: -6335409530604852063} + - {fileID: -1216621516061285780} + - {fileID: 3959858460715838825} + - {fileID: -7743500325797982168} + - {fileID: 4644742534064026673} + - {fileID: -4463884970436517307} + - {fileID: -6288072647309666549} + - {fileID: 7518938298396184218} + - {fileID: -1410297666881709256} + - {fileID: -7750755424749557576} + - {fileID: -5139089513906902183} +--- !u!114 &853819529557874667 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 06437c1ff663d574d9447842ba0a72e4, type: 3} + m_Name: ScreenSpaceLensFlare + m_EditorClassIdentifier: + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 + tintColor: + m_OverrideState: 1 + m_Value: {r: 1, g: 1, b: 1, a: 1} + bloomMip: + m_OverrideState: 1 + m_Value: 1 + firstFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + secondaryFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + warpedFlareIntensity: + m_OverrideState: 1 + m_Value: 1 + warpedFlareScale: + m_OverrideState: 1 + m_Value: {x: 1, y: 1} + samples: + m_OverrideState: 1 + m_Value: 1 + sampleDimmer: + m_OverrideState: 1 + m_Value: 0.5 + vignetteEffect: + m_OverrideState: 1 + m_Value: 1 + startingPosition: + m_OverrideState: 1 + m_Value: 1.25 + scale: + m_OverrideState: 1 + m_Value: 1.5 + streaksIntensity: + m_OverrideState: 1 + m_Value: 0 + streaksLength: + m_OverrideState: 1 + m_Value: 0.5 + streaksOrientation: + m_OverrideState: 1 + m_Value: 0 + streaksThreshold: + m_OverrideState: 1 + m_Value: 0.25 + resolution: + m_OverrideState: 1 + m_Value: 4 + chromaticAbberationIntensity: + m_OverrideState: 1 + m_Value: 0.5 +--- !u!114 &1052315754049611418 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 558a8e2b6826cf840aae193990ba9f2e, type: 3} + m_Name: ShadowsMidtonesHighlights + m_EditorClassIdentifier: + active: 1 + shadows: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + midtones: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + highlights: + m_OverrideState: 1 + m_Value: {x: 1, y: 1, z: 1, w: 0} + shadowsStart: + m_OverrideState: 1 + m_Value: 0 + shadowsEnd: + m_OverrideState: 1 + m_Value: 0.3 + highlightsStart: + m_OverrideState: 1 + m_Value: 0.55 + highlightsEnd: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &1666464333004379222 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3eb4b772797da9440885e8bd939e9560, type: 3} + m_Name: ColorCurves + m_EditorClassIdentifier: + active: 1 + master: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + red: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + green: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + blue: + m_OverrideState: 1 + m_Value: + k__BackingField: 2 + m_Loop: 0 + m_ZeroValue: 0 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 1 + outSlope: 1 + tangentMode: 0 + weightedMode: 0 + inWeight: 0 + outWeight: 0 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + hueVsHue: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + hueVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 1 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + satVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + lumVsSat: + m_OverrideState: 1 + m_Value: + k__BackingField: 0 + m_Loop: 0 + m_ZeroValue: 0.5 + m_Range: 1 + m_Curve: + serializedVersion: 2 + m_Curve: [] + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!114 &1918650496244738858 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e021b4c809a781e468c2988c016ebbea, type: 3} + m_Name: ColorLookup + m_EditorClassIdentifier: + active: 1 + texture: + m_OverrideState: 1 + m_Value: {fileID: 0} + dimension: 1 + contribution: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &3959858460715838825 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c01700fd266d6914ababb731e09af2eb, type: 3} + m_Name: DepthOfField + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 0 + gaussianStart: + m_OverrideState: 1 + m_Value: 10 + gaussianEnd: + m_OverrideState: 1 + m_Value: 30 + gaussianMaxRadius: + m_OverrideState: 1 + m_Value: 1 + highQualitySampling: + m_OverrideState: 1 + m_Value: 0 + focusDistance: + m_OverrideState: 1 + m_Value: 10 + aperture: + m_OverrideState: 1 + m_Value: 5.6 + focalLength: + m_OverrideState: 1 + m_Value: 50 + bladeCount: + m_OverrideState: 1 + m_Value: 5 + bladeCurvature: + m_OverrideState: 1 + m_Value: 1 + bladeRotation: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &4251301726029935498 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 74955a4b0b4243bc87231e8b59ed9140, type: 3} + m_Name: TestVolume + m_EditorClassIdentifier: + active: 1 + param: + m_OverrideState: 1 + m_Value: 123 +--- !u!114 &4644742534064026673 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 81180773991d8724ab7f2d216912b564, type: 3} + m_Name: ChromaticAberration + m_EditorClassIdentifier: + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &6940869943325143175 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: VolumeComponentSupportedOnAnySRP + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEngine.Rendering.Tests:VolumeComponentEditorSupportedOnTests/VolumeComponentSupportedOnAnySRP + active: 1 +--- !u!114 &7173750748008157695 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 899c54efeace73346a0a16faa3afe726, type: 3} + m_Name: Vignette + m_EditorClassIdentifier: + active: 1 + color: + m_OverrideState: 1 + m_Value: {r: 0, g: 0, b: 0, a: 1} + center: + m_OverrideState: 1 + m_Value: {x: 0.5, y: 0.5} + intensity: + m_OverrideState: 1 + m_Value: 0 + smoothness: + m_OverrideState: 1 + m_Value: 0.2 + rounded: + m_OverrideState: 1 + m_Value: 0 +--- !u!114 &7518938298396184218 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c5e1dc532bcb41949b58bc4f2abfbb7e, type: 3} + m_Name: LensDistortion + m_EditorClassIdentifier: + active: 1 + intensity: + m_OverrideState: 1 + m_Value: 0 + xMultiplier: + m_OverrideState: 1 + m_Value: 1 + yMultiplier: + m_OverrideState: 1 + m_Value: 1 + center: + m_OverrideState: 1 + m_Value: {x: 0.5, y: 0.5} + scale: + m_OverrideState: 1 + m_Value: 1 +--- !u!114 &9001657382290151224 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: cdfbdbb87d3286943a057f7791b43141, type: 3} + m_Name: ChannelMixer + m_EditorClassIdentifier: + active: 1 + redOutRedIn: + m_OverrideState: 1 + m_Value: 100 + redOutGreenIn: + m_OverrideState: 1 + m_Value: 0 + redOutBlueIn: + m_OverrideState: 1 + m_Value: 0 + greenOutRedIn: + m_OverrideState: 1 + m_Value: 0 + greenOutGreenIn: + m_OverrideState: 1 + m_Value: 100 + greenOutBlueIn: + m_OverrideState: 1 + m_Value: 0 + blueOutRedIn: + m_OverrideState: 1 + m_Value: 0 + blueOutGreenIn: + m_OverrideState: 1 + m_Value: 0 + blueOutBlueIn: + m_OverrideState: 1 + m_Value: 100 +--- !u!114 &9122958982931076880 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 0} + m_Name: CopyPasteTestComponent1 + m_EditorClassIdentifier: Unity.RenderPipelines.Core.Editor.Tests:UnityEditor.Rendering.Tests:VolumeComponentCopyPasteTests/CopyPasteTestComponent1 + active: 1 + p1: + m_OverrideState: 1 + m_Value: 0 + p2: + m_OverrideState: 1 + m_Value: 0 diff --git a/Assets/Settings/DefaultVolumeProfile.asset.meta b/Assets/Settings/DefaultVolumeProfile.asset.meta new file mode 100644 index 0000000..53b314a --- /dev/null +++ b/Assets/Settings/DefaultVolumeProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab09877e2e707104187f6f83e2f62510 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Mobile_RPAsset.asset b/Assets/Settings/Mobile_RPAsset.asset new file mode 100644 index 0000000..0fdefd1 --- /dev/null +++ b/Assets/Settings/Mobile_RPAsset.asset @@ -0,0 +1,135 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: Mobile_RPAsset + m_EditorClassIdentifier: + k_AssetVersion: 12 + k_AssetPreviousVersion: 12 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: 65bc7dbf4170f435aa868c779acfb082, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 0 + m_RequireOpaqueTexture: 0 + m_OpaqueDownsampling: 0 + m_SupportsTerrainHoles: 1 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 0.8 + m_UpscalingFilter: 3 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_LightProbeSystem: 0 + m_ProbeVolumeMemoryBudget: 1024 + m_ProbeVolumeBlendingMemoryBudget: 256 + m_SupportProbeVolumeGPUStreaming: 0 + m_SupportProbeVolumeDiskStreaming: 0 + m_SupportProbeVolumeScenarios: 0 + m_SupportProbeVolumeScenarioBlending: 0 + m_ProbeVolumeSHBands: 1 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 1024 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 0 + m_AdditionalLightsShadowmapResolution: 2048 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 1 + m_ReflectionProbeBoxProjection: 1 + m_ShadowDistance: 50 + m_ShadowCascadeCount: 1 + m_Cascade2Split: 0.25 + m_Cascade3Split: {x: 0.1, y: 0.3} + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467} + m_CascadeBorder: 0.2 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 0 + m_ConservativeEnclosingSphere: 1 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 1024 + m_AdditionalLightsCookieFormat: 1 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 1 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 0 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 1 + m_SupportDataDrivenLensFlare: 1 + m_SupportScreenSpaceLensFlare: 1 + m_GPUResidentDrawerMode: 0 + m_UseLegacyLightmaps: 0 + m_SmallMeshScreenPercentage: 0 + m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_VolumeProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 4 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 1 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 0 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 0 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 0 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_PrefilterUseLegacyLightmaps: 0 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} diff --git a/Assets/Settings/Mobile_RPAsset.asset.meta b/Assets/Settings/Mobile_RPAsset.asset.meta new file mode 100644 index 0000000..3660d15 --- /dev/null +++ b/Assets/Settings/Mobile_RPAsset.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e6cbd92db86f4b18aec3ed561671858 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/Mobile_Renderer.asset b/Assets/Settings/Mobile_Renderer.asset new file mode 100644 index 0000000..01e59d4 --- /dev/null +++ b/Assets/Settings/Mobile_Renderer.asset @@ -0,0 +1,66 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: Mobile_Renderer + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, + type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, + type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 0} + probeVolumeFragmentationDebugShader: {fileID: 0} + probeVolumeOffsetDebugShader: {fileID: 0} + probeVolumeSamplingDebugShader: {fileID: 0} + probeSamplingDebugMesh: {fileID: 0} + probeSamplingDebugTexture: {fileID: 0} + probeVolumeBlendStatesCS: {fileID: 0} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 1 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 0 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 0 +--- !u!114 &1002035807535710140 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a0ec52cecc795714f93f274c2e71e87b, type: 3} + m_Name: GlobalVolumeFeature + m_EditorClassIdentifier: + m_Active: 1 + _baseProfile: {fileID: 11400000, guid: f2d4d916a6612574cad220d125febbf2, type: 2} diff --git a/Assets/Settings/Mobile_Renderer.asset.meta b/Assets/Settings/Mobile_Renderer.asset.meta new file mode 100644 index 0000000..a3588b1 --- /dev/null +++ b/Assets/Settings/Mobile_Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 65bc7dbf4170f435aa868c779acfb082 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/PC_RPAsset.asset b/Assets/Settings/PC_RPAsset.asset new file mode 100644 index 0000000..8b30a06 --- /dev/null +++ b/Assets/Settings/PC_RPAsset.asset @@ -0,0 +1,135 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: PC_RPAsset + m_EditorClassIdentifier: + k_AssetVersion: 12 + k_AssetPreviousVersion: 12 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: f288ae1f4751b564a96ac7587541f7a2, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 1 + m_RequireOpaqueTexture: 1 + m_OpaqueDownsampling: 1 + m_SupportsTerrainHoles: 1 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_LightProbeSystem: 0 + m_ProbeVolumeMemoryBudget: 1024 + m_ProbeVolumeBlendingMemoryBudget: 256 + m_SupportProbeVolumeGPUStreaming: 0 + m_SupportProbeVolumeDiskStreaming: 0 + m_SupportProbeVolumeScenarios: 0 + m_SupportProbeVolumeScenarioBlending: 0 + m_ProbeVolumeSHBands: 1 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 2048 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 1 + m_AdditionalLightsShadowmapResolution: 2048 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 1 + m_ReflectionProbeBoxProjection: 1 + m_ShadowDistance: 50 + m_ShadowCascadeCount: 4 + m_Cascade2Split: 0.25 + m_Cascade3Split: {x: 0.1, y: 0.3} + m_Cascade4Split: {x: 0.12299999, y: 0.2926, z: 0.53599995} + m_CascadeBorder: 0.107758604 + m_ShadowDepthBias: 0.1 + m_ShadowNormalBias: 0.5 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 1 + m_ConservativeEnclosingSphere: 1 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 3 + m_AdditionalLightsCookieResolution: 2048 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 1 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 0 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_SupportScreenSpaceLensFlare: 1 + m_GPUResidentDrawerMode: 0 + m_UseLegacyLightmaps: 0 + m_SmallMeshScreenPercentage: 0 + m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_VolumeProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2} + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 4 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 1 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 1 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 0 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 0 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 0 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 0 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 0 + m_PrefilterSoftShadowsQualityLow: 0 + m_PrefilterSoftShadowsQualityMedium: 0 + m_PrefilterSoftShadowsQualityHigh: 0 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_PrefilterUseLegacyLightmaps: 0 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} diff --git a/Assets/Settings/PC_RPAsset.asset.meta b/Assets/Settings/PC_RPAsset.asset.meta new file mode 100644 index 0000000..e286b2f --- /dev/null +++ b/Assets/Settings/PC_RPAsset.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b83569d67af61e458304325a23e5dfd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/PC_Renderer.asset b/Assets/Settings/PC_Renderer.asset new file mode 100644 index 0000000..475b02e --- /dev/null +++ b/Assets/Settings/PC_Renderer.asset @@ -0,0 +1,95 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: PC_Renderer + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, + type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, + type: 3} + probeVolumeResources: + probeVolumeDebugShader: {fileID: 4800000, guid: e5c6678ed2aaa91408dd3df699057aae, + type: 3} + probeVolumeFragmentationDebugShader: {fileID: 4800000, guid: 03cfc4915c15d504a9ed85ecc404e607, + type: 3} + probeVolumeOffsetDebugShader: {fileID: 4800000, guid: 53a11f4ebaebf4049b3638ef78dc9664, + type: 3} + probeVolumeSamplingDebugShader: {fileID: 4800000, guid: 8f96cd657dc40064aa21efcc7e50a2e7, + type: 3} + probeSamplingDebugMesh: {fileID: -3555484719484374845, guid: 57d7c4c16e2765b47a4d2069b311bffe, + type: 3} + probeSamplingDebugTexture: {fileID: 2800000, guid: 24ec0e140fb444a44ab96ee80844e18e, + type: 3} + probeVolumeBlendStatesCS: {fileID: 7200000, guid: b9a23f869c4fd45f19c5ada54dd82176, + type: 3} + m_RendererFeatures: + - {fileID: 7833122117494664109} + m_RendererFeatureMap: ad6b866f10d7b46c + m_UseNativeRenderPass: 1 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 1 + stencilCompareFunction: 3 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 2 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 0 +--- !u!114 &7833122117494664109 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f62c9c65cf3354c93be831c8bc075510, type: 3} + m_Name: ScreenSpaceAmbientOcclusion + m_EditorClassIdentifier: + m_Active: 1 + m_Settings: + AOMethod: 0 + Downsample: 0 + AfterOpaque: 0 + Source: 1 + NormalSamples: 1 + Intensity: 0.4 + DirectLightingStrength: 0.25 + Radius: 0.3 + Samples: 1 + BlurQuality: 0 + Falloff: 100 + SampleCount: -1 + m_BlueNoise256Textures: + - {fileID: 2800000, guid: 36f118343fc974119bee3d09e2111500, type: 3} + - {fileID: 2800000, guid: 4b7b083e6b6734e8bb2838b0b50a0bc8, type: 3} + - {fileID: 2800000, guid: c06cc21c692f94f5fb5206247191eeee, type: 3} + - {fileID: 2800000, guid: cb76dd40fa7654f9587f6a344f125c9a, type: 3} + - {fileID: 2800000, guid: e32226222ff144b24bf3a5a451de54bc, type: 3} + - {fileID: 2800000, guid: 3302065f671a8450b82c9ddf07426f3a, type: 3} + - {fileID: 2800000, guid: 56a77a3e8d64f47b6afe9e3c95cb57d5, type: 3} + m_Shader: {fileID: 4800000, guid: 0849e84e3d62649e8882e9d6f056a017, type: 3} diff --git a/Assets/Settings/PC_Renderer.asset.meta b/Assets/Settings/PC_Renderer.asset.meta new file mode 100644 index 0000000..ddae6a5 --- /dev/null +++ b/Assets/Settings/PC_Renderer.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f288ae1f4751b564a96ac7587541f7a2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/SampleSceneProfile.asset b/Assets/Settings/SampleSceneProfile.asset new file mode 100644 index 0000000..c1b0f63 --- /dev/null +++ b/Assets/Settings/SampleSceneProfile.asset @@ -0,0 +1,159 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7893295128165547882 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3} + m_Name: Bloom + m_EditorClassIdentifier: + active: 1 + skipIterations: + m_OverrideState: 1 + m_Value: 0 + threshold: + m_OverrideState: 1 + m_Value: 1 + intensity: + m_OverrideState: 1 + m_Value: 0.25 + scatter: + m_OverrideState: 1 + m_Value: 0.5 + clamp: + m_OverrideState: 0 + m_Value: 65472 + tint: + m_OverrideState: 0 + m_Value: {r: 1, g: 1, b: 1, a: 1} + highQualityFiltering: + m_OverrideState: 1 + m_Value: 1 + downscale: + m_OverrideState: 0 + m_Value: 0 + maxIterations: + m_OverrideState: 0 + m_Value: 6 + dirtTexture: + m_OverrideState: 0 + m_Value: {fileID: 0} + dimension: 1 + dirtIntensity: + m_OverrideState: 0 + m_Value: 0 +--- !u!114 &-3357603926938260329 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 899c54efeace73346a0a16faa3afe726, type: 3} + m_Name: Vignette + m_EditorClassIdentifier: + active: 1 + color: + m_OverrideState: 0 + m_Value: {r: 0, g: 0, b: 0, a: 1} + center: + m_OverrideState: 0 + m_Value: {x: 0.5, y: 0.5} + intensity: + m_OverrideState: 1 + m_Value: 0.2 + smoothness: + m_OverrideState: 0 + m_Value: 0.2 + rounded: + m_OverrideState: 0 + m_Value: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3} + m_Name: SampleSceneProfile + m_EditorClassIdentifier: + components: + - {fileID: 849379129802519247} + - {fileID: -7893295128165547882} + - {fileID: 7391319092446245454} + - {fileID: -3357603926938260329} +--- !u!114 &849379129802519247 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3} + m_Name: Tonemapping + m_EditorClassIdentifier: + active: 1 + mode: + m_OverrideState: 1 + m_Value: 1 + neutralHDRRangeReductionMode: + m_OverrideState: 0 + m_Value: 2 + acesPreset: + m_OverrideState: 0 + m_Value: 3 + hueShiftAmount: + m_OverrideState: 0 + m_Value: 0 + detectPaperWhite: + m_OverrideState: 1 + m_Value: 0 + paperWhite: + m_OverrideState: 1 + m_Value: 234 + detectBrightnessLimits: + m_OverrideState: 1 + m_Value: 1 + minNits: + m_OverrideState: 1 + m_Value: 0.005 + maxNits: + m_OverrideState: 1 + m_Value: 647 +--- !u!114 &7391319092446245454 +MonoBehaviour: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ccf1aba9553839d41ae37dd52e9ebcce, type: 3} + m_Name: MotionBlur + m_EditorClassIdentifier: + active: 0 + mode: + m_OverrideState: 0 + m_Value: 0 + quality: + m_OverrideState: 1 + m_Value: 2 + intensity: + m_OverrideState: 1 + m_Value: 0.6 + clamp: + m_OverrideState: 0 + m_Value: 0.05 diff --git a/Assets/Settings/SampleSceneProfile.asset.meta b/Assets/Settings/SampleSceneProfile.asset.meta new file mode 100644 index 0000000..b82270c --- /dev/null +++ b/Assets/Settings/SampleSceneProfile.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10fc4df2da32a41aaa32d77bc913491c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset new file mode 100644 index 0000000..f27001e --- /dev/null +++ b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset @@ -0,0 +1,255 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2ec995e51a6e251468d2a3fd8a686257, type: 3} + m_Name: UniversalRenderPipelineGlobalSettings + m_EditorClassIdentifier: + m_ShaderStrippingSetting: + m_Version: 0 + m_ExportShaderVariants: 1 + m_ShaderVariantLogLevel: 0 + m_StripRuntimeDebugShaders: 1 + m_URPShaderStrippingSetting: + m_Version: 0 + m_StripUnusedPostProcessingVariants: 1 + m_StripUnusedVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + m_ShaderVariantLogLevel: 0 + m_ExportShaderVariants: 1 + m_StripDebugVariants: 1 + m_StripUnusedPostProcessingVariants: 1 + m_StripUnusedVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + supportRuntimeDebugDisplay: 0 + m_EnableRenderGraph: 0 + m_Settings: + m_SettingsList: + m_List: + - rid: 6852985685364965376 + - rid: 6852985685364965377 + - rid: 6852985685364965378 + - rid: 6852985685364965379 + - rid: 6852985685364965380 + - rid: 6852985685364965381 + - rid: 6852985685364965382 + - rid: 6852985685364965383 + - rid: 6852985685364965384 + - rid: 6852985685364965385 + - rid: 6852985685364965386 + - rid: 6852985685364965387 + - rid: 6852985685364965388 + - rid: 6852985685364965389 + - rid: 6852985685364965390 + - rid: 6852985685364965391 + - rid: 6852985685364965392 + - rid: 6852985685364965393 + - rid: 6852985685364965394 + - rid: 8712630790384254976 + - rid: 8472278536239448064 + m_RuntimeSettings: + m_List: [] + m_AssetVersion: 8 + m_ObsoleteDefaultVolumeProfile: {fileID: 0} + m_RenderingLayerNames: + - Light Layer default + - Light Layer 1 + - Light Layer 2 + - Light Layer 3 + - Light Layer 4 + - Light Layer 5 + - Light Layer 6 + - Light Layer 7 + m_ValidRenderingLayers: 0 + lightLayerName0: Light Layer default + lightLayerName1: Light Layer 1 + lightLayerName2: Light Layer 2 + lightLayerName3: Light Layer 3 + lightLayerName4: Light Layer 4 + lightLayerName5: Light Layer 5 + lightLayerName6: Light Layer 6 + lightLayerName7: Light Layer 7 + apvScenesData: + obsoleteSceneBounds: + m_Keys: [] + m_Values: [] + obsoleteHasProbeVolumes: + m_Keys: [] + m_Values: + references: + version: 2 + RefIds: + - rid: 6852985685364965376 + type: {class: URPShaderStrippingSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_StripUnusedPostProcessingVariants: 1 + m_StripUnusedVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + - rid: 6852985685364965377 + type: {class: UniversalRenderPipelineEditorShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_AutodeskInteractive: {fileID: 4800000, guid: 0e9d5a909a1f7e84882a534d0d11e49f, type: 3} + m_AutodeskInteractiveTransparent: {fileID: 4800000, guid: 5c81372d981403744adbdda4433c9c11, type: 3} + m_AutodeskInteractiveMasked: {fileID: 4800000, guid: 80aa867ac363ac043847b06ad71604cd, type: 3} + m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + m_DefaultSpeedTree7Shader: {fileID: 4800000, guid: 0f4122b9a743b744abe2fb6a0a88868b, type: 3} + m_DefaultSpeedTree8Shader: {fileID: -6465566751694194690, guid: 9920c1f1781549a46ba081a2a15a16ec, type: 3} + m_DefaultSpeedTree9Shader: {fileID: -6465566751694194690, guid: cbd3e1cc4ae141c42a30e33b4d666a61, type: 3} + - rid: 6852985685364965378 + type: {class: UniversalRendererResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + m_CameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + m_StencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + m_DBufferClear: {fileID: 4800000, guid: f056d8bd2a1c7e44e9729144b4c70395, type: 3} + - rid: 6852985685364965379 + type: {class: UniversalRenderPipelineDebugShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_DebugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + m_HdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_ProbeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3} + - rid: 6852985685364965380 + type: {class: UniversalRenderPipelineRuntimeShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_FallbackErrorShader: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + m_BlitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + m_CoreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + m_CoreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + m_SamplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + - rid: 6852985685364965381 + type: {class: UniversalRenderPipelineRuntimeTextures, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 1 + m_BlueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + m_BayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_DebugFontTex: {fileID: 2800000, guid: 26a413214480ef144b2915d6ff4d0beb, type: 3} + - rid: 6852985685364965382 + type: {class: Renderer2DResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_LightShader: {fileID: 4800000, guid: 3f6c848ca3d7bca4bbe846546ac701a1, type: 3} + m_ProjectedShadowShader: {fileID: 4800000, guid: ce09d4a80b88c5a4eb9768fab4f1ee00, type: 3} + m_SpriteShadowShader: {fileID: 4800000, guid: 44fc62292b65ab04eabcf310e799ccf6, type: 3} + m_SpriteUnshadowShader: {fileID: 4800000, guid: de02b375720b5c445afe83cd483bedf3, type: 3} + m_GeometryShadowShader: {fileID: 4800000, guid: 19349a0f9a7ed4c48a27445bcf92e5e1, type: 3} + m_GeometryUnshadowShader: {fileID: 4800000, guid: 77774d9009bb81447b048c907d4c6273, type: 3} + m_FallOffLookup: {fileID: 2800000, guid: 5688ab254e4c0634f8d6c8e0792331ca, type: 3} + m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + m_DefaultLitMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} + m_DefaultUnlitMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2} + m_DefaultMaskMaterial: {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2} + - rid: 6852985685364965383 + type: {class: UniversalRenderPipelineEditorMaterials, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_DefaultMaterial: {fileID: 2100000, guid: 31321ba15b8f8eb4c954353edc038b1d, type: 2} + m_DefaultParticleMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2} + m_DefaultLineMaterial: {fileID: 2100000, guid: e823cd5b5d27c0f4b8256e7c12ee3e6d, type: 2} + m_DefaultTerrainMaterial: {fileID: 2100000, guid: 594ea882c5a793440b60ff72d896021e, type: 2} + m_DefaultDecalMaterial: {fileID: 2100000, guid: 31d0dcc6f2dd4e4408d18036a2c93862, type: 2} + - rid: 6852985685364965384 + type: {class: URPDefaultVolumeProfileSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_VolumeProfile: {fileID: 11400000, guid: ab09877e2e707104187f6f83e2f62510, type: 2} + - rid: 6852985685364965385 + type: {class: RenderGraphSettings, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_EnableRenderCompatibilityMode: 0 + - rid: 6852985685364965386 + type: {class: GPUResidentDrawerResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.GPUDriven.Runtime} + data: + m_Version: 0 + m_InstanceDataBufferCopyKernels: {fileID: 7200000, guid: f984aeb540ded8b4fbb8a2047ab5b2e2, type: 3} + m_InstanceDataBufferUploadKernels: {fileID: 7200000, guid: 53864816eb00f2343b60e1a2c5a262ef, type: 3} + m_TransformUpdaterKernels: {fileID: 7200000, guid: 2a567b9b2733f8d47a700c3c85bed75b, type: 3} + m_WindDataUpdaterKernels: {fileID: 7200000, guid: fde76746e4fd0ed418c224f6b4084114, type: 3} + m_OccluderDepthPyramidKernels: {fileID: 7200000, guid: 08b2b5fb307b0d249860612774a987da, type: 3} + m_InstanceOcclusionCullingKernels: {fileID: 7200000, guid: f6d223acabc2f974795a5a7864b50e6c, type: 3} + m_OcclusionCullingDebugKernels: {fileID: 7200000, guid: b23e766bcf50ca4438ef186b174557df, type: 3} + m_DebugOcclusionTestPS: {fileID: 4800000, guid: d3f0849180c2d0944bc71060693df100, type: 3} + m_DebugOccluderPS: {fileID: 4800000, guid: b3c92426a88625841ab15ca6a7917248, type: 3} + - rid: 6852985685364965387 + type: {class: STP/RuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_setupCS: {fileID: 7200000, guid: 33be2e9a5506b2843bdb2bdff9cad5e1, type: 3} + m_preTaaCS: {fileID: 7200000, guid: a679dba8ec4d9ce45884a270b0e22dda, type: 3} + m_taaCS: {fileID: 7200000, guid: 3923900e2b41b5e47bc25bfdcbcdc9e6, type: 3} + - rid: 6852985685364965388 + type: {class: ProbeVolumeBakingResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + dilationShader: {fileID: 7200000, guid: 6bb382f7de370af41b775f54182e491d, type: 3} + subdivideSceneCS: {fileID: 7200000, guid: bb86f1f0af829fd45b2ebddda1245c22, type: 3} + voxelizeSceneShader: {fileID: 4800000, guid: c8b6a681c7b4e2e4785ffab093907f9e, type: 3} + traceVirtualOffsetCS: {fileID: -6772857160820960102, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3} + traceVirtualOffsetRT: {fileID: -5126288278712620388, guid: ff2cbab5da58bf04d82c5f34037ed123, type: 3} + skyOcclusionCS: {fileID: -6772857160820960102, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3} + skyOcclusionRT: {fileID: -5126288278712620388, guid: 5a2a534753fbdb44e96c3c78b5a6999d, type: 3} + renderingLayerCS: {fileID: -6772857160820960102, guid: 94a070d33e408384bafc1dea4a565df9, type: 3} + renderingLayerRT: {fileID: -5126288278712620388, guid: 94a070d33e408384bafc1dea4a565df9, type: 3} + - rid: 6852985685364965389 + type: {class: ProbeVolumeGlobalSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + m_ProbeVolumeDisableStreamingAssets: 0 + - rid: 6852985685364965390 + type: {class: ProbeVolumeDebugResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + probeVolumeDebugShader: {fileID: 4800000, guid: 3b21275fd12d65f49babb5286f040f2d, type: 3} + probeVolumeFragmentationDebugShader: {fileID: 4800000, guid: 3a80877c579b9144ebdcc6d923bca303, type: 3} + probeVolumeSamplingDebugShader: {fileID: 4800000, guid: bf54e6528c79a224e96346799064c393, type: 3} + probeVolumeOffsetDebugShader: {fileID: 4800000, guid: db8bd7436dc2c5f4c92655307d198381, type: 3} + probeSamplingDebugMesh: {fileID: -3555484719484374845, guid: 20be25aac4e22ee49a7db76fb3df6de2, type: 3} + numbersDisplayTex: {fileID: 2800000, guid: 73fe53b428c5b3440b7e87ee830b608a, type: 3} + - rid: 6852985685364965391 + type: {class: IncludeAdditionalRPAssets, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_version: 0 + m_IncludeReferencedInScenes: 0 + m_IncludeAssetsByLabel: 0 + m_LabelToInclude: + - rid: 6852985685364965392 + type: {class: ShaderStrippingSetting, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 0 + m_ExportShaderVariants: 1 + m_ShaderVariantLogLevel: 0 + m_StripRuntimeDebugShaders: 1 + - rid: 6852985685364965393 + type: {class: ProbeVolumeRuntimeResources, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 1 + probeVolumeBlendStatesCS: {fileID: 7200000, guid: a3f7b8c99de28a94684cb1daebeccf5d, type: 3} + probeVolumeUploadDataCS: {fileID: 7200000, guid: 0951de5992461754fa73650732c4954c, type: 3} + probeVolumeUploadDataL2CS: {fileID: 7200000, guid: 6196f34ed825db14b81fb3eb0ea8d931, type: 3} + - rid: 6852985685364965394 + type: {class: RenderGraphGlobalSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_version: 0 + m_EnableCompilationCaching: 1 + m_EnableValidityChecks: 1 + - rid: 8472278536239448064 + type: {class: UniversalRenderPipelineRuntimeXRResources, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_xrOcclusionMeshPS: {fileID: 4800000, guid: 4431b1f1f743fbf4eb310a967890cbea, type: 3} + m_xrMirrorViewPS: {fileID: 4800000, guid: d5a307c014552314b9f560906d708772, type: 3} + m_xrMotionVector: {fileID: 4800000, guid: f89aac1e4f84468418fe30e611dff395, type: 3} + - rid: 8712630790384254976 + type: {class: RenderGraphUtilsResources, ns: UnityEngine.Rendering.RenderGraphModule.Util, asm: Unity.RenderPipelines.Core.Runtime} + data: + m_Version: 0 + m_CoreCopyPS: {fileID: 4800000, guid: 12dc59547ea167a4ab435097dd0f9add, type: 3} diff --git a/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta new file mode 100644 index 0000000..81b84f2 --- /dev/null +++ b/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18dc0cd2c080841dea60987a38ce93fa +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo.meta b/Assets/TutorialInfo.meta new file mode 100644 index 0000000..a700bca --- /dev/null +++ b/Assets/TutorialInfo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ba062aa6c92b140379dbc06b43dd3b9b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Icons.meta b/Assets/TutorialInfo/Icons.meta new file mode 100644 index 0000000..1d19fb9 --- /dev/null +++ b/Assets/TutorialInfo/Icons.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8a0c9218a650547d98138cd835033977 +folderAsset: yes +timeCreated: 1484670163 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Icons/URP.png b/Assets/TutorialInfo/Icons/URP.png new file mode 100644 index 0000000..6194a80 Binary files /dev/null and b/Assets/TutorialInfo/Icons/URP.png differ diff --git a/Assets/TutorialInfo/Icons/URP.png.meta b/Assets/TutorialInfo/Icons/URP.png.meta new file mode 100644 index 0000000..0f2cab0 --- /dev/null +++ b/Assets/TutorialInfo/Icons/URP.png.meta @@ -0,0 +1,134 @@ +fileFormatVersion: 2 +guid: 727a75301c3d24613a3ebcec4a24c2c8 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMasterTextureLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 0 + aniso: 1 + mipBias: 0 + wrapU: 1 + wrapV: 1 + wrapW: 0 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 3 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + nameFileIdTable: {} + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Layout.wlt b/Assets/TutorialInfo/Layout.wlt new file mode 100644 index 0000000..7b50a25 --- /dev/null +++ b/Assets/TutorialInfo/Layout.wlt @@ -0,0 +1,654 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12004, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PixelRect: + serializedVersion: 2 + x: 0 + y: 45 + width: 1666 + height: 958 + m_ShowMode: 4 + m_Title: + m_RootView: {fileID: 6} + m_MinSize: {x: 950, y: 542} + m_MaxSize: {x: 10000, y: 10000} +--- !u!114 &2 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 466 + width: 290 + height: 442 + m_MinSize: {x: 234, y: 271} + m_MaxSize: {x: 10004, y: 10021} + m_ActualView: {fileID: 14} + m_Panes: + - {fileID: 14} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &3 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 4} + - {fileID: 2} + m_Position: + serializedVersion: 2 + x: 973 + y: 0 + width: 290 + height: 908 + m_MinSize: {x: 234, y: 492} + m_MaxSize: {x: 10004, y: 14042} + vertical: 1 + controlID: 226 +--- !u!114 &4 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 290 + height: 466 + m_MinSize: {x: 204, y: 221} + m_MaxSize: {x: 4004, y: 4021} + m_ActualView: {fileID: 17} + m_Panes: + - {fileID: 17} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &5 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 466 + width: 973 + height: 442 + m_MinSize: {x: 202, y: 221} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 15} + m_Panes: + - {fileID: 15} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &6 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12008, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 7} + - {fileID: 8} + - {fileID: 9} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1666 + height: 958 + m_MinSize: {x: 950, y: 542} + m_MaxSize: {x: 10000, y: 10000} +--- !u!114 &7 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12011, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1666 + height: 30 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} + m_LastLoadedLayoutName: Tutorial +--- !u!114 &8 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 10} + - {fileID: 3} + - {fileID: 11} + m_Position: + serializedVersion: 2 + x: 0 + y: 30 + width: 1666 + height: 908 + m_MinSize: {x: 713, y: 492} + m_MaxSize: {x: 18008, y: 14042} + vertical: 0 + controlID: 74 +--- !u!114 &9 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12042, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 938 + width: 1666 + height: 20 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} +--- !u!114 &10 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 12} + - {fileID: 5} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 973 + height: 908 + m_MinSize: {x: 202, y: 442} + m_MaxSize: {x: 4002, y: 8042} + vertical: 1 + controlID: 75 +--- !u!114 &11 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 1263 + y: 0 + width: 403 + height: 908 + m_MinSize: {x: 277, y: 71} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 13} + m_Panes: + - {fileID: 13} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &12 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 973 + height: 466 + m_MinSize: {x: 202, y: 221} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 16} + m_Panes: + - {fileID: 16} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &13 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12019, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 0 + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Inspector + m_Image: {fileID: -6905738622615590433, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 0 + m_Pos: + serializedVersion: 2 + x: 2 + y: 19 + width: 401 + height: 887 + m_ScrollPosition: {x: 0, y: 0} + m_InspectorMode: 0 + m_PreviewResizer: + m_CachedPref: -160 + m_ControlHash: -371814159 + m_PrefName: Preview_InspectorPreview + m_PreviewWindow: {fileID: 0} +--- !u!114 &14 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12014, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 0 + m_MinSize: {x: 230, y: 250} + m_MaxSize: {x: 10000, y: 10000} + m_TitleContent: + m_Text: Project + m_Image: {fileID: -7501376956915960154, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 0 + m_Pos: + serializedVersion: 2 + x: 2 + y: 19 + width: 286 + height: 421 + m_SearchFilter: + m_NameFilter: + m_ClassNames: [] + m_AssetLabels: [] + m_AssetBundleNames: [] + m_VersionControlStates: [] + m_ReferencingInstanceIDs: + m_ScenePaths: [] + m_ShowAllHits: 0 + m_SearchArea: 0 + m_Folders: + - Assets + m_ViewMode: 0 + m_StartGridSize: 64 + m_LastFolders: + - Assets + m_LastFoldersGridSize: -1 + m_LastProjectPath: /Users/danielbrauer/Unity Projects/New Unity Project 47 + m_IsLocked: 0 + m_FolderTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: ee240000 + m_LastClickedID: 9454 + m_ExpandedIDs: ee24000000ca9a3bffffff7f + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_AssetTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 68fbffff + m_LastClickedID: 0 + m_ExpandedIDs: ee240000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_ListAreaState: + m_SelectedInstanceIDs: 68fbffff + m_LastClickedInstanceID: -1176 + m_HadKeyboardFocusLastEvent: 0 + m_ExpandedInstanceIDs: c6230000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_NewAssetIndexInList: -1 + m_ScrollPosition: {x: 0, y: 0} + m_GridSize: 64 + m_DirectoriesAreaWidth: 110 +--- !u!114 &15 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12015, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 1 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Game + m_Image: {fileID: -2087823869225018852, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 32 + m_Pos: + serializedVersion: 2 + x: 0 + y: 19 + width: 971 + height: 421 + m_MaximizeOnPlay: 0 + m_Gizmos: 0 + m_Stats: 0 + m_SelectedSizes: 00000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_TargetDisplay: 0 + m_ZoomArea: + m_HRangeLocked: 0 + m_VRangeLocked: 0 + m_HBaseRangeMin: -242.75 + m_HBaseRangeMax: 242.75 + m_VBaseRangeMin: -101 + m_VBaseRangeMax: 101 + m_HAllowExceedBaseRangeMin: 1 + m_HAllowExceedBaseRangeMax: 1 + m_VAllowExceedBaseRangeMin: 1 + m_VAllowExceedBaseRangeMax: 1 + m_ScaleWithWindow: 0 + m_HSlider: 0 + m_VSlider: 0 + m_IgnoreScrollWheelUntilClicked: 0 + m_EnableMouseInput: 1 + m_EnableSliderZoom: 0 + m_UniformScale: 1 + m_UpDirection: 1 + m_DrawArea: + serializedVersion: 2 + x: 0 + y: 17 + width: 971 + height: 404 + m_Scale: {x: 2, y: 2} + m_Translation: {x: 485.5, y: 202} + m_MarginLeft: 0 + m_MarginRight: 0 + m_MarginTop: 0 + m_MarginBottom: 0 + m_LastShownAreaInsideMargins: + serializedVersion: 2 + x: -242.75 + y: -101 + width: 485.5 + height: 202 + m_MinimalGUI: 1 + m_defaultScale: 2 + m_TargetTexture: {fileID: 0} + m_CurrentColorSpace: 0 + m_LastWindowPixelSize: {x: 1942, y: 842} + m_ClearInEditMode: 1 + m_NoCameraWarning: 1 + m_LowResolutionForAspectRatios: 01000000000100000100 +--- !u!114 &16 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12013, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 1 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Scene + m_Image: {fileID: 2318424515335265636, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 32 + m_Pos: + serializedVersion: 2 + x: 0 + y: 19 + width: 971 + height: 445 + m_SceneLighting: 1 + lastFramingTime: 0 + m_2DMode: 0 + m_isRotationLocked: 0 + m_AudioPlay: 0 + m_Position: + m_Target: {x: 0, y: 0, z: 0} + speed: 2 + m_Value: {x: 0, y: 0, z: 0} + m_RenderMode: 0 + m_ValidateTrueMetals: 0 + m_SceneViewState: + showFog: 1 + showMaterialUpdate: 0 + showSkybox: 1 + showFlares: 1 + showImageEffects: 1 + grid: + xGrid: + m_Target: 0 + speed: 2 + m_Value: 0 + yGrid: + m_Target: 1 + speed: 2 + m_Value: 1 + zGrid: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Rotation: + m_Target: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + speed: 2 + m_Value: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_Size: + m_Target: 10 + speed: 2 + m_Value: 10 + m_Ortho: + m_Target: 0 + speed: 2 + m_Value: 0 + m_LastSceneViewRotation: {x: 0, y: 0, z: 0, w: 0} + m_LastSceneViewOrtho: 0 + m_ReplacementShader: {fileID: 0} + m_ReplacementString: + m_LastLockedObject: {fileID: 0} + m_ViewIsLockedToObject: 0 +--- !u!114 &17 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12061, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_AutoRepaintOnSceneChange: 0 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Hierarchy + m_Image: {fileID: -590624980919486359, guid: 0000000000000000d000000000000000, + type: 0} + m_Tooltip: + m_DepthBufferBits: 0 + m_Pos: + serializedVersion: 2 + x: 2 + y: 19 + width: 286 + height: 445 + m_TreeViewState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 68fbffff + m_LastClickedID: -1176 + m_ExpandedIDs: 7efbffff00000000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 0 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_ExpandedScenes: + - + m_CurrenRootInstanceID: 0 + m_Locked: 0 + m_CurrentSortingName: TransformSorting diff --git a/Assets/TutorialInfo/Layout.wlt.meta b/Assets/TutorialInfo/Layout.wlt.meta new file mode 100644 index 0000000..c0c8c77 --- /dev/null +++ b/Assets/TutorialInfo/Layout.wlt.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eabc9546105bf4accac1fd62a63e88e6 +timeCreated: 1487337779 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts.meta b/Assets/TutorialInfo/Scripts.meta new file mode 100644 index 0000000..02da605 --- /dev/null +++ b/Assets/TutorialInfo/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 5a9bcd70e6a4b4b05badaa72e827d8e0 +folderAsset: yes +timeCreated: 1475835190 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts/Editor.meta b/Assets/TutorialInfo/Scripts/Editor.meta new file mode 100644 index 0000000..f59f099 --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3ad9b87dffba344c89909c6d1b1c17e1 +folderAsset: yes +timeCreated: 1475593892 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs new file mode 100644 index 0000000..ad55eca --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs @@ -0,0 +1,242 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; +using System; +using System.IO; +using System.Reflection; + +[CustomEditor(typeof(Readme))] +[InitializeOnLoad] +public class ReadmeEditor : Editor +{ + static string s_ShowedReadmeSessionStateName = "ReadmeEditor.showedReadme"; + + static string s_ReadmeSourceDirectory = "Assets/TutorialInfo"; + + const float k_Space = 16f; + + static ReadmeEditor() + { + EditorApplication.delayCall += SelectReadmeAutomatically; + } + + static void RemoveTutorial() + { + if (EditorUtility.DisplayDialog("Remove Readme Assets", + + $"All contents under {s_ReadmeSourceDirectory} will be removed, are you sure you want to proceed?", + "Proceed", + "Cancel")) + { + if (Directory.Exists(s_ReadmeSourceDirectory)) + { + FileUtil.DeleteFileOrDirectory(s_ReadmeSourceDirectory); + FileUtil.DeleteFileOrDirectory(s_ReadmeSourceDirectory + ".meta"); + } + else + { + Debug.Log($"Could not find the Readme folder at {s_ReadmeSourceDirectory}"); + } + + var readmeAsset = SelectReadme(); + if (readmeAsset != null) + { + var path = AssetDatabase.GetAssetPath(readmeAsset); + FileUtil.DeleteFileOrDirectory(path + ".meta"); + FileUtil.DeleteFileOrDirectory(path); + } + + AssetDatabase.Refresh(); + } + } + + static void SelectReadmeAutomatically() + { + if (!SessionState.GetBool(s_ShowedReadmeSessionStateName, false)) + { + var readme = SelectReadme(); + SessionState.SetBool(s_ShowedReadmeSessionStateName, true); + + if (readme && !readme.loadedLayout) + { + LoadLayout(); + readme.loadedLayout = true; + } + } + } + + static void LoadLayout() + { + var assembly = typeof(EditorApplication).Assembly; + var windowLayoutType = assembly.GetType("UnityEditor.WindowLayout", true); + var method = windowLayoutType.GetMethod("LoadWindowLayout", BindingFlags.Public | BindingFlags.Static); + method.Invoke(null, new object[] { Path.Combine(Application.dataPath, "TutorialInfo/Layout.wlt"), false }); + } + + static Readme SelectReadme() + { + var ids = AssetDatabase.FindAssets("Readme t:Readme"); + if (ids.Length == 1) + { + var readmeObject = AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(ids[0])); + + Selection.objects = new UnityEngine.Object[] { readmeObject }; + + return (Readme)readmeObject; + } + else + { + Debug.Log("Couldn't find a readme"); + return null; + } + } + + protected override void OnHeaderGUI() + { + var readme = (Readme)target; + Init(); + + var iconWidth = Mathf.Min(EditorGUIUtility.currentViewWidth / 3f - 20f, 128f); + + GUILayout.BeginHorizontal("In BigTitle"); + { + if (readme.icon != null) + { + GUILayout.Space(k_Space); + GUILayout.Label(readme.icon, GUILayout.Width(iconWidth), GUILayout.Height(iconWidth)); + } + GUILayout.Space(k_Space); + GUILayout.BeginVertical(); + { + + GUILayout.FlexibleSpace(); + GUILayout.Label(readme.title, TitleStyle); + GUILayout.FlexibleSpace(); + } + GUILayout.EndVertical(); + GUILayout.FlexibleSpace(); + } + GUILayout.EndHorizontal(); + } + + public override void OnInspectorGUI() + { + var readme = (Readme)target; + Init(); + + foreach (var section in readme.sections) + { + if (!string.IsNullOrEmpty(section.heading)) + { + GUILayout.Label(section.heading, HeadingStyle); + } + + if (!string.IsNullOrEmpty(section.text)) + { + GUILayout.Label(section.text, BodyStyle); + } + + if (!string.IsNullOrEmpty(section.linkText)) + { + if (LinkLabel(new GUIContent(section.linkText))) + { + Application.OpenURL(section.url); + } + } + + GUILayout.Space(k_Space); + } + + if (GUILayout.Button("Remove Readme Assets", ButtonStyle)) + { + RemoveTutorial(); + } + } + + bool m_Initialized; + + GUIStyle LinkStyle + { + get { return m_LinkStyle; } + } + + [SerializeField] + GUIStyle m_LinkStyle; + + GUIStyle TitleStyle + { + get { return m_TitleStyle; } + } + + [SerializeField] + GUIStyle m_TitleStyle; + + GUIStyle HeadingStyle + { + get { return m_HeadingStyle; } + } + + [SerializeField] + GUIStyle m_HeadingStyle; + + GUIStyle BodyStyle + { + get { return m_BodyStyle; } + } + + [SerializeField] + GUIStyle m_BodyStyle; + + GUIStyle ButtonStyle + { + get { return m_ButtonStyle; } + } + + [SerializeField] + GUIStyle m_ButtonStyle; + + void Init() + { + if (m_Initialized) + return; + m_BodyStyle = new GUIStyle(EditorStyles.label); + m_BodyStyle.wordWrap = true; + m_BodyStyle.fontSize = 14; + m_BodyStyle.richText = true; + + m_TitleStyle = new GUIStyle(m_BodyStyle); + m_TitleStyle.fontSize = 26; + + m_HeadingStyle = new GUIStyle(m_BodyStyle); + m_HeadingStyle.fontStyle = FontStyle.Bold; + m_HeadingStyle.fontSize = 18; + + m_LinkStyle = new GUIStyle(m_BodyStyle); + m_LinkStyle.wordWrap = false; + + // Match selection color which works nicely for both light and dark skins + m_LinkStyle.normal.textColor = new Color(0x00 / 255f, 0x78 / 255f, 0xDA / 255f, 1f); + m_LinkStyle.stretchWidth = false; + + m_ButtonStyle = new GUIStyle(EditorStyles.miniButton); + m_ButtonStyle.fontStyle = FontStyle.Bold; + + m_Initialized = true; + } + + bool LinkLabel(GUIContent label, params GUILayoutOption[] options) + { + var position = GUILayoutUtility.GetRect(label, LinkStyle, options); + + Handles.BeginGUI(); + Handles.color = LinkStyle.normal.textColor; + Handles.DrawLine(new Vector3(position.xMin, position.yMax), new Vector3(position.xMax, position.yMax)); + Handles.color = Color.white; + Handles.EndGUI(); + + EditorGUIUtility.AddCursorRect(position, MouseCursor.Link); + + return GUI.Button(position, label, LinkStyle); + } +} diff --git a/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs.meta b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs.meta new file mode 100644 index 0000000..f038618 --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Editor/ReadmeEditor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 476cc7d7cd9874016adc216baab94a0a +timeCreated: 1484146680 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TutorialInfo/Scripts/Readme.cs b/Assets/TutorialInfo/Scripts/Readme.cs new file mode 100644 index 0000000..95f6269 --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Readme.cs @@ -0,0 +1,16 @@ +using System; +using UnityEngine; + +public class Readme : ScriptableObject +{ + public Texture2D icon; + public string title; + public Section[] sections; + public bool loadedLayout; + + [Serializable] + public class Section + { + public string heading, text, linkText, url; + } +} diff --git a/Assets/TutorialInfo/Scripts/Readme.cs.meta b/Assets/TutorialInfo/Scripts/Readme.cs.meta new file mode 100644 index 0000000..935153f --- /dev/null +++ b/Assets/TutorialInfo/Scripts/Readme.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: fcf7219bab7fe46a1ad266029b2fee19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: + - icon: {instanceID: 0} + executionOrder: 0 + icon: {fileID: 2800000, guid: a186f8a87ca4f4d3aa864638ad5dfb65, type: 3} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/manifest.json b/Packages/manifest.json new file mode 100644 index 0000000..9fae179 --- /dev/null +++ b/Packages/manifest.json @@ -0,0 +1,47 @@ +{ + "dependencies": { + "com.unity.ai.navigation": "2.0.4", + "com.unity.collab-proxy": "2.5.2", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.inputsystem": "1.11.2", + "com.unity.multiplayer.center": "1.0.0", + "com.unity.render-pipelines.universal": "17.0.3", + "com.unity.test-framework": "1.4.5", + "com.unity.timeline": "1.8.7", + "com.unity.ugui": "2.0.0", + "com.unity.visualscripting": "1.9.4", + "com.unity.modules.accessibility": "1.0.0", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json new file mode 100644 index 0000000..5e7908c --- /dev/null +++ b/Packages/packages-lock.json @@ -0,0 +1,465 @@ +{ + "dependencies": { + "com.unity.ai.navigation": { + "version": "2.0.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.burst": { + "version": "1.8.18", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.collab-proxy": { + "version": "2.5.2", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, + "com.unity.collections": { + "version": "2.5.1", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.8.17", + "com.unity.nuget.mono-cecil": "1.11.4", + "com.unity.test-framework": "1.4.5", + "com.unity.test-framework.performance": "3.0.3" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.ext.nunit": { + "version": "2.0.5", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, + "com.unity.ide.rider": { + "version": "3.0.31", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.22", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.inputsystem": { + "version": "1.11.2", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.mathematics": { + "version": "1.3.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, + "com.unity.multiplayer.center": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.nuget.mono-cecil": { + "version": "1.11.4", + "depth": 3, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, + "com.unity.render-pipelines.core": { + "version": "17.0.3", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.burst": "1.8.14", + "com.unity.mathematics": "1.3.2", + "com.unity.ugui": "2.0.0", + "com.unity.collections": "2.4.3", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.rendering.light-transport": "1.0.1" + } + }, + "com.unity.render-pipelines.universal": { + "version": "17.0.3", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.0.3", + "com.unity.shadergraph": "17.0.3", + "com.unity.render-pipelines.universal-config": "17.0.3" + } + }, + "com.unity.render-pipelines.universal-config": { + "version": "17.0.3", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.0.3" + } + }, + "com.unity.rendering.light-transport": { + "version": "1.0.1", + "depth": 2, + "source": "builtin", + "dependencies": { + "com.unity.collections": "2.2.0", + "com.unity.mathematics": "1.2.4", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.searcher": { + "version": "4.9.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.cn" + }, + "com.unity.shadergraph": { + "version": "17.0.3", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.render-pipelines.core": "17.0.3", + "com.unity.searcher": "4.9.2" + } + }, + "com.unity.test-framework": { + "version": "1.4.5", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "2.0.3", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.test-framework.performance": { + "version": "3.0.3", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.31", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.timeline": { + "version": "1.8.7", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.ugui": { + "version": "2.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.9.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.cn" + }, + "com.unity.modules.accessibility": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.hierarchycore": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.hierarchycore": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/ProjectSettings/AudioManager.asset b/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..27287fe --- /dev/null +++ b/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 diff --git a/ProjectSettings/ClusterInputManager.asset b/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/ProjectSettings/DynamicsManager.asset b/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..fc90ab9 --- /dev/null +++ b/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 diff --git a/ProjectSettings/EditorBuildSettings.asset b/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..d057ba3 --- /dev/null +++ b/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,13 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 99c9720ab356a0642a771bea13969a05 + m_configObjects: + com.unity.input.settings.actions: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_UseUCBPForAssetBundles: 0 diff --git a/ProjectSettings/EditorSettings.asset b/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..d85f86b --- /dev/null +++ b/ProjectSettings/EditorSettings.asset @@ -0,0 +1,48 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerCacheSize: 10 + m_SpritePackerPaddingPower: 1 + m_Bc7TextureCompressor: 0 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_EnableEditorAsyncCPUTextureLoading: 0 + m_AsyncShaderCompilation: 1 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 1 + m_EnterPlayModeOptions: 0 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 + m_InspectorUseIMGUIDefaultInspector: 0 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 0 + m_AssetPipelineMode: 1 + m_RefreshImportMode: 0 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableAuth: 0 + m_CacheServerEnableTls: 0 + m_CacheServerValidationMode: 2 + m_CacheServerDownloadBatchSize: 128 + m_EnableEnlightenBakedGI: 0 + m_ReferencedClipsExactNaming: 1 diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..aa5a1c3 --- /dev/null +++ b/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,70 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 16 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_PreloadShadersBatchTimeLimit: -1 + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, + type: 2} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_BrgStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_RenderPipelineGlobalSettingsMap: + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 18dc0cd2c080841dea60987a38ce93fa, + type: 2} + m_LightsUseLinearIntensity: 1 + m_LightsUseColorTemperature: 1 + m_LogWhenShaderIsCompiled: 0 + m_LightProbeOutsideHullStrategy: 0 + m_CameraRelativeLightCulling: 0 + m_CameraRelativeShadowCulling: 0 diff --git a/ProjectSettings/InputManager.asset b/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..b16147e --- /dev/null +++ b/ProjectSettings/InputManager.asset @@ -0,0 +1,487 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 diff --git a/ProjectSettings/MemorySettings.asset b/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/ProjectSettings/MultiplayerManager.asset b/ProjectSettings/MultiplayerManager.asset new file mode 100644 index 0000000..2a93664 --- /dev/null +++ b/ProjectSettings/MultiplayerManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!655991488 &1 +MultiplayerManager: + m_ObjectHideFlags: 0 + m_EnableMultiplayerRoles: 0 + m_StrippingTypes: {} diff --git a/ProjectSettings/NavMeshAreas.asset b/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..76c059b --- /dev/null +++ b/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,37 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + m_DismissPreviewPackagesInUse: 0 + oneTimeWarningShown: 0 + oneTimeDeprecatedPopUpShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.cn + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_ConfigSource: 0 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -892 + m_OriginalInstanceId: -894 + m_LoadAssets: 0 diff --git a/ProjectSettings/Physics2DSettings.asset b/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..6c5cf8a --- /dev/null +++ b/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 0 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/ProjectSettings/PresetManager.asset b/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..f53b9c4 --- /dev/null +++ b/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,945 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 28 + productGUID: 07ea5224a41670d4dbac5fdaee068076 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: StoicGoose.Unity + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1024 + defaultScreenHeight: 768 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 1 + unsupportedMSAAFallback: 0 + m_SpriteBatchMaxVertexCount: 65535 + m_SpriteBatchVertexThreshold: 300 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 0 + androidBlitType: 0 + androidResizeableActivity: 1 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + androidPredictiveBackSupport: 0 + androidApplicationEntry: 2 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + dedicatedServerOptimizations: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + meshDeformation: 2 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchMaxWorkerMultiple: 8 + switchNVNGraphicsFirmwareMemory: 32 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 1 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 + bundleVersion: 0.1.0 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 + useHDRDisplay: 0 + hdrBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.4 + androidMinAspectRatio: 1 + applicationIdentifier: + Android: com.UnityTechnologies.com.unity.template.urpblank + Standalone: com.Unity-Technologies.com.unity.template.urp-blank + iPhone: com.Unity-Technologies.com.unity.template.urp-blank + buildNumber: + Standalone: 0 + VisionOS: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 1 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 23 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + androidSplitApplicationBinary: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + strictShaderVariantMatching: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSSimulatorArchitecture: 0 + iOSTargetOSVersionString: 13.0 + tvOSSdkVersion: 0 + tvOSSimulatorArchitecture: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 13.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + metalCompileShaderBinary: 0 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: 3c72c65a16f0acb438eed22b8b16c24a + templatePackageId: com.unity.template.urp-blank@17.0.11 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 2 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidEnableArm64MTE: 0 + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + AndroidReportGooglePlayAppDependencies: 1 + androidSymbolsSizeThreshold: 800 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + - m_BuildTarget: tvOS + m_Icons: + - m_Textures: [] + m_Width: 1280 + m_Height: 768 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 800 + m_Height: 480 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 400 + m_Height: 240 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 4640 + m_Height: 1440 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 2320 + m_Height: 720 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 3840 + m_Height: 1440 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 1920 + m_Height: 720 + m_Kind: 1 + m_SubKind: + m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: [] + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 0 + m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: + - serializedVersion: 2 + m_BuildTarget: Android + m_EncodingQuality: 1 + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: + - m_BuildTarget: Android + m_Encoding: 1 + m_BuildTargetDefaultTextureCompressionFormat: + - serializedVersion: 3 + m_BuildTarget: Android + m_Formats: 03000000 + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + editorGfxJobOverride: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 11.0 + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchDisableHTCSPlayerConnection: 0 + switchUseNewStyleFilepaths: 0 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + switchUpgradedPlayerSettingsToNMETA: 0 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 0 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLEnableWebGPU: 0 + webGLPowerPreference: 2 + webGLWebAssemblyTable: 0 + webGLWebAssemblyBigInt: 0 + webGLCloseOnQuit: 0 + webWasm2023: 0 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: + Android: 1 + il2cppCompilerConfiguration: {} + il2cppCodeGeneration: {} + il2cppStacktraceInformation: {} + managedStrippingLevel: + Android: 1 + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + QNX: 1 + ReservedCFE: 1 + VisionOS: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + editorAssembliesCompatibilityLevel: 1 + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: StoicGoose.Unity + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: StoicGoose.Unity + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: {} + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 1 + embeddedLinuxEnableGamepadInput: 0 + hmiCpuConfiguration: + hmiLogStartupTiming: 0 + qnxGraphicConfPath: + apiCompatibilityLevel: 6 + captureStartupLogs: {} + activeInputHandler: 2 + windowsGamepadBackendHint: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 + androidVulkanDenyFilterList: [] + androidVulkanAllowFilterList: [] diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..d8106cd --- /dev/null +++ b/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 6000.0.26f1c1 +m_EditorVersionWithRevision: 6000.0.26f1c1 (7aa86d9db9ca) diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..f55198a --- /dev/null +++ b/ProjectSettings/QualitySettings.asset @@ -0,0 +1,134 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 1 + m_QualitySettings: + - serializedVersion: 4 + name: Mobile + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 1 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 11400000, guid: 5e6cbd92db86f4b18aec3ed561671858, + type: 2} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: + - Standalone + - serializedVersion: 4 + name: PC + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + globalTextureMipmapLimit: 0 + textureMipmapLimitSettings: [] + anisotropicTextures: 2 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 1 + useLegacyDetailDistribution: 1 + adaptiveVsync: 0 + vSyncCount: 0 + realtimeGICPUUsage: 100 + adaptiveVsyncExtraA: 0 + adaptiveVsyncExtraB: 0 + lodBias: 2 + maximumLODLevel: 0 + enableLODCrossFade: 1 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, + type: 2} + terrainQualityOverrides: 0 + terrainPixelError: 1 + terrainDetailDensityScale: 1 + terrainBasemapDistance: 1000 + terrainDetailDistance: 80 + terrainTreeDistance: 5000 + terrainBillboardStart: 50 + terrainFadeLength: 5 + terrainMaxTrees: 50 + excludedTargetPlatforms: + - Android + - iPhone + m_TextureMipmapLimitGroupNames: [] + m_PerPlatformDefaultQuality: + Android: 0 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Lumin: 0 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + Server: 0 + Stadia: 0 + Standalone: 1 + WebGL: 0 + Windows Store Apps: 0 + XboxOne: 0 + iPhone: 0 + tvOS: 0 diff --git a/ProjectSettings/SceneTemplateSettings.json b/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..ede5887 --- /dev/null +++ b/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/ProjectSettings/ShaderGraphSettings.asset b/ProjectSettings/ShaderGraphSettings.asset new file mode 100644 index 0000000..e66042a --- /dev/null +++ b/ProjectSettings/ShaderGraphSettings.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3} + m_Name: + m_EditorClassIdentifier: + shaderVariantLimit: 128 + customInterpolatorErrorThreshold: 32 + customInterpolatorWarningThreshold: 16 + customHeatmapValues: {fileID: 0} diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..6413d11 --- /dev/null +++ b/ProjectSettings/TagManager.asset @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 + m_RenderingLayers: + - Default + - Light Layer 1 + - Light Layer 2 + - Light Layer 3 + - Light Layer 4 + - Light Layer 5 + - Light Layer 6 + - Light Layer 7 + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - diff --git a/ProjectSettings/TimeManager.asset b/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/ProjectSettings/URPProjectSettings.asset b/ProjectSettings/URPProjectSettings.asset new file mode 100644 index 0000000..08faf03 --- /dev/null +++ b/ProjectSettings/URPProjectSettings.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 247994e1f5a72c2419c26a37e9334c01, type: 3} + m_Name: + m_EditorClassIdentifier: + m_LastMaterialVersion: 9 diff --git a/ProjectSettings/UnityConnectSettings.asset b/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..4c136ae --- /dev/null +++ b/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,38 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_CNEventUrl: https://cdp.cloud.unity.cn/v1/events + m_CNConfigUrl: https://cdp.cloud.unity.cn/config + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity.cn + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 1 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/ProjectSettings/VFXManager.asset b/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..3a95c98 --- /dev/null +++ b/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/ProjectSettings/VersionControlSettings.asset b/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/ProjectSettings/XRSettings.asset b/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file