BlueBear icon

D3D.cpp

BlueBear | PRO | 10/25/18 05:08:53 PM UTC | 0 ⭐ | 413 👁️ | Never ⏰ | []
C++ (WinAPI) |

0 B

|

None

|

0 👍

/

0 👎

#pragma once
 
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN    // Exclude rarely-used stuff from Windows headers.
#endif
 
#pragma comment(lib, "d3d12.lib")
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3dcompiler.lib")
 
#include <Vector.hpp>
#include "Types.hpp"
 
#include "Allocator.hpp"
#include "Memory.hpp"
#include "Thread.hpp"
 
#include <d3d12.h>
#include <dxgi1_4.h>
#include <D3Dcompiler.h>
#include <DirectXMath.h>
#include "d3dx12.h"
#include <string>
#include <wrl.h>
 
#include <windows.h>
 
using namespace DirectX;
using namespace Microsoft::WRL;
 
#define SAFE_RELEASE(p) { if ( (p) ) { (p)->Release(); (p) = 0; } }
 
struct ConstantBufferPerObject
{
    XMFLOAT4X4 wvpMat;
};
 
struct Vertex
{
    Vertex(float x, float y, float z, float r, float g, float b, float a) : pos(x, y, z), color(r, g, b, a) {}
    XMFLOAT3 pos;
    XMFLOAT4 color;
};
 
HWND hwnd = NULL;
int32 Width = 800;
int32 Height = 600;
bool FullScreen = false;
bool Running = true;
bool InitializeWindow(HINSTANCE hInstance, int32 ShowWnd, bool fullscreen);
bool InitD3D();
void Update();
void UpdatePipeline();
void Render();
void Cleanup();
void WaitForPreviousFrame();
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
 
const int32 frameBufferCount = 3;
ComPtr<ID3D12Device> device;
IDXGISwapChain3* swapChain;
ID3D12CommandQueue* commandQueue;
ID3D12DescriptorHeap* rtvDescriptorHeap;
ID3D12Resource* renderTargets[frameBufferCount];
ID3D12CommandAllocator* commandAllocator[frameBufferCount];
ID3D12GraphicsCommandList* commandList;
ID3D12Fence* fence[frameBufferCount];
HANDLE fenceEvent;
uint64 fenceValue[frameBufferCount];
SIZE_T frameIndex;
int32 rtvDescriptorSize;
ID3D12PipelineState* pipelineStateObject;
ID3D12RootSignature* rootSignature;
D3D12_VIEWPORT viewport;
D3D12_RECT scissorRect;
ID3D12Resource* vertexBuffer;
ID3D12Resource* indexBuffer;
D3D12_VERTEX_BUFFER_VIEW vertexBufferView;
D3D12_INDEX_BUFFER_VIEW indexBufferView;
ID3D12Resource* depthStencilBuffer;
ID3D12DescriptorHeap* dsDescriptorHeap;
int32 ConstantBufferPerObjectAlignedSize = (sizeof(ConstantBufferPerObject) + 255) & ~255;
ConstantBufferPerObject cbPerObject;
ID3D12Resource* constantBufferUploadHeaps[frameBufferCount];
uint8* cbvGPUAddress[frameBufferCount];
 
XMFLOAT4X4 cameraProjMat;
XMFLOAT4X4 cameraViewMat;
XMFLOAT4 cameraPosition;
XMFLOAT4 cameraTarget;
XMFLOAT4 cameraUp;
XMFLOAT4X4 cube1WorldMat;
XMFLOAT4X4 cube1RotMat;
XMFLOAT4 cube1Position;
XMFLOAT4X4 cube2WorldMat;
XMFLOAT4X4 cube2RotMat;
XMFLOAT4 cube2PositionOffset;
int32 numCubeIndices;
 
struct SThreadTest
{
    uint8 DoWork()
    {
        for (SIZE_T i = 0; i < 100; ++i)
        {
            OutputDebugStringA("thread stuff\n");
        }
        return 0;
    }
};
 
struct SThreadTest2
{
    uint8 DoWork()
    {
        for (SIZE_T i = 0; i < 100; ++i)
        {
            OutputDebugStringA("thread stuff2\n");
        }
        return 0;
    }
};
 
int32 WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int32 nShowCmd)
{
    using namespace Aberration::Memory;
    using namespace Aberration::OS;
    //default memory allocator, basically aligned malloc and aligned free
    IAllocator* allocator = GlobalAllocator;
 
    //allocate single int
    auto mem = TMemory<int>::Allocate(allocator);
    //do something with memory mem
    //free single int
    TMemory<int>::Free(allocator, mem);
 
    //allocate an array of 10 ints, non initialized
    auto array = TMemory<int[]>::Allocate(allocator, 10);
    //do something with memory array
    //free array of ints
    TMemory<int[]>::Free(allocator, array, 10);
 
    //allocate an array of 10 ints, initialized
    auto defaultinitedarray = TMemory<int[]>::Allocate(allocator, 10, 7);
    //do something with memory defaultinitedarray
    //free array of ints
    TMemory<int[]>::Free(allocator, defaultinitedarray, 10);
 
 
    Aberration::OS::FThread::FMainFunctionType ThreadMain;
 
    SThreadTest ThreadTest;
    ThreadMain.Bind<SThreadTest, &SThreadTest::DoWork>(&ThreadTest);
 
    Aberration::OS::FThread::FMainFunctionType ThreadMain2;
    SThreadTest2 ThreadTest2;
    ThreadMain2.Bind<SThreadTest2, &SThreadTest2::DoWork>(&ThreadTest2);
 
    //FThread TestThread;
    //auto err = TestThread.Create(ThreadMain, "test", 0);
    //FThread TestThread2;
    //err = TestThread2.Create(ThreadMain2, "test2", 0);
 
    /*for (SIZE_T i = 0; i < 100; ++i)
    {
        OutputDebugStringA("main thread\n");
    }
    */
    if (!InitializeWindow(hInstance, nShowCmd, FullScreen))
    {
        MessageBox(0, L"Window Initialization - Failed", L"Error", MB_OK);
        return 1;
    }
 
    if (!InitD3D())
    {
        MessageBox(0, L"Failed to initialize direct3d 12", L"Error", MB_OK);
        Cleanup();
        return 1;
    }
 
    MSG msg = MSG();
    while (Running)
    {
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
                break;
 
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        else
        {
            Update();
            Render();
        }
    }
 
    WaitForPreviousFrame();
    CloseHandle(fenceEvent);
    Cleanup();
    return 0;
}
 
bool InitializeWindow(HINSTANCE hInstance, int32 ShowWnd, bool fullscreen)
{
    if (fullscreen)
    {
        HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
        MONITORINFO mi = { sizeof(mi) };
        GetMonitorInfo(hmon, &mi);
        Width = mi.rcMonitor.right - mi.rcMonitor.left;
        Height = mi.rcMonitor.bottom - mi.rcMonitor.top;
    }
 
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = NULL;
    wc.cbWndExtra = NULL;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"AberrationEngineWindowName";
    wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"Error registering class", L"Error", MB_OK | MB_ICONERROR);
        return false;
    }
    hwnd = CreateWindowEx(NULL, L"AberrationEngineWindowName", L"Aberration Engine", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, Width, Height, NULL, NULL, hInstance, NULL);
    if (!hwnd)
    {
        MessageBox(NULL, L"Error creating window", L"Error", MB_OK | MB_ICONERROR);
        return false;
    }
    if (fullscreen)
    {
        SetWindowLong(hwnd, GWL_STYLE, 0);
    }
    ShowWindow(hwnd, ShowWnd);
    UpdateWindow(hwnd);
    return true;
}
 
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_KEYDOWN:
        if (wParam == VK_ESCAPE) 
        {
            if (MessageBox(0, L"Are you sure you want to exit?", L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES)
            {
                Running = false;
                DestroyWindow(hwnd);
            }
        }
        return 0;
 
    case WM_DESTROY:
        Running = false;
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}
 
bool InitD3D()
{
    IDXGIFactory4* dxgiFactory;
    auto hr = CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory));
    if (FAILED(hr))
    {
        return false;
    }
 
    IDXGIAdapter1* adapter;
    int32 adapterIndex = 0;
    bool adapterFound = false;
    while (dxgiFactory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND)
    {
        DXGI_ADAPTER_DESC1 desc;
        adapter->GetDesc1(&desc);
 
        if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)
        {
            adapterIndex++;
            continue;
        }
        auto hresult = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, _uuidof(ID3D12Device), nullptr);
        if (SUCCEEDED(hresult))
        {
            adapterFound = true;
            break;
        }
        adapterIndex++;
    }
 
 
    if (!adapterFound)
    {
        return false;
    }
    {
        // Create the device
        auto res = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device));
        if (FAILED(res))
        {
            return false;
        }
    }
 
    D3D12_COMMAND_QUEUE_DESC cqDesc = {};
    cqDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
    cqDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
    if (FAILED(device->CreateCommandQueue(&cqDesc, IID_PPV_ARGS(&commandQueue))))
    {
        return false;
    }
 
    DXGI_MODE_DESC backBufferDesc = {};
    backBufferDesc.Width = Width;
    backBufferDesc.Height = Height;
    backBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    
    DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
    swapChainDesc.BufferCount = frameBufferCount;
    swapChainDesc.BufferDesc = backBufferDesc;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
    swapChainDesc.OutputWindow = hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.Windowed = !FullScreen;
 
    IDXGISwapChain* tempSwapChain;
    dxgiFactory->CreateSwapChain(commandQueue, &swapChainDesc, &tempSwapChain);
    swapChain = static_cast<IDXGISwapChain3*>(tempSwapChain);
    frameIndex = swapChain->GetCurrentBackBufferIndex();
 
    D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = D3D12_DESCRIPTOR_HEAP_DESC();
    rtvHeapDesc.NumDescriptors = frameBufferCount;
    rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
    rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    hr = device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&rtvDescriptorHeap));
    if (FAILED(hr))
    {
        return false;
    }
 
    rtvDescriptorSize = device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
    D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
 
    for (SIZE_T i = 0; i < frameBufferCount; i++)
    {
        hr = swapChain->GetBuffer((UINT)i, IID_PPV_ARGS(&renderTargets[i]));
        if (FAILED(hr))
        {
            return false;
        }
        device->CreateRenderTargetView(renderTargets[i], nullptr, rtvHandle);
        rtvHandle.ptr += 1 * rtvDescriptorSize;
    }
 
    for (SIZE_T i = 0; i < frameBufferCount; i++)
    {
        if (FAILED(device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAllocator[i]))))
        {
            return false;
        }
    }
 
    if (FAILED(device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator[frameIndex], NULL, IID_PPV_ARGS(&commandList))))
    {
        return false;
    }
 
    for (SIZE_T i = 0; i < frameBufferCount; i++)
    {
        hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence[i]));
        if (FAILED(hr))
        {
            return false;
        }
        fenceValue[i] = 0;
    }
 
    fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
    if (fenceEvent == nullptr)
    {
        return false;
    }
 
    D3D12_ROOT_DESCRIPTOR rootCBVDescriptor;
    rootCBVDescriptor.RegisterSpace = 0;
    rootCBVDescriptor.ShaderRegister = 0;
 
    D3D12_ROOT_PARAMETER rootParameters[1];
    rootParameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
    rootParameters[0].Descriptor = rootCBVDescriptor;
    rootParameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL;
 
    D3D12_ROOT_SIGNATURE_DESC rootSignatureDesc = D3D12_ROOT_SIGNATURE_DESC();
    rootSignatureDesc.NumParameters = _countof(rootParameters);
    rootSignatureDesc.pParameters = rootParameters;
    rootSignatureDesc.NumStaticSamplers = 0;
    rootSignatureDesc.pStaticSamplers = nullptr;
    rootSignatureDesc.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
        D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS |
        D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
        D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
        D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS;
 
    ID3DBlob* signature;
    if (FAILED(D3D12SerializeRootSignature(&rootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION_1, &signature, nullptr))) { return false; }
    if (FAILED(device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&rootSignature)))) { return false; }
 
    ID3DBlob* vertexShader;
    ID3DBlob* errorBuff;
    hr = D3DCompileFromFile(L"BaseShader.vs.hlsl", nullptr, nullptr, "main", "vs_5_0", D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &vertexShader, &errorBuff);
    if (FAILED(hr))
    {
        OutputDebugStringA((LPCSTR)errorBuff->GetBufferPointer());
        return false;
    }
 
    D3D12_SHADER_BYTECODE vertexShaderBytecode = {};
    vertexShaderBytecode.BytecodeLength = vertexShader->GetBufferSize();
    vertexShaderBytecode.pShaderBytecode = vertexShader->GetBufferPointer();
 
    // compile pixel shader
    ID3DBlob* pixelShader;
    hr = D3DCompileFromFile(L"BaseShader.ps.hlsl", nullptr, nullptr, "main", "ps_5_0", D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &pixelShader, &errorBuff);
    if (FAILED(hr))
    {
        OutputDebugStringA((LPCSTR)errorBuff->GetBufferPointer());
        return false;
    }
 
    D3D12_SHADER_BYTECODE pixelShaderBytecode = {};
    pixelShaderBytecode.BytecodeLength = pixelShader->GetBufferSize();
    pixelShaderBytecode.pShaderBytecode = pixelShader->GetBufferPointer();
 
    const D3D12_INPUT_ELEMENT_DESC inputLayout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
        { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
    };
 
    D3D12_INPUT_LAYOUT_DESC inputLayoutDesc = {};
    inputLayoutDesc.NumElements = sizeof(inputLayout) / sizeof(D3D12_INPUT_ELEMENT_DESC);
    inputLayoutDesc.pInputElementDescs = inputLayout;
 
    D3D12_RASTERIZER_DESC rasterDesc = D3D12_RASTERIZER_DESC();
    rasterDesc.FillMode = D3D12_FILL_MODE_SOLID;
    rasterDesc.CullMode = D3D12_CULL_MODE_BACK;
    rasterDesc.FrontCounterClockwise = FALSE;
    rasterDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS;
    rasterDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP;
    rasterDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS;
    rasterDesc.DepthClipEnable = TRUE;
    rasterDesc.MultisampleEnable = FALSE;
    rasterDesc.AntialiasedLineEnable = FALSE;
    rasterDesc.ForcedSampleCount = 0;
    rasterDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
 
    D3D12_BLEND_DESC blendDesc = D3D12_BLEND_DESC();
    blendDesc.IndependentBlendEnable = FALSE;
    const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc =
    {
        FALSE,FALSE,
        D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
        D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD,
        D3D12_LOGIC_OP_NOOP,
        D3D12_COLOR_WRITE_ENABLE_ALL,
    };
    for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i)
    {
        blendDesc.RenderTarget[i] = defaultRenderTargetBlendDesc;
    }
 
    D3D12_DEPTH_STENCIL_DESC dsDesc = D3D12_DEPTH_STENCIL_DESC();
    dsDesc.DepthEnable = TRUE;
    dsDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL;
    dsDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS;
    dsDesc.StencilEnable = FALSE;
    dsDesc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
    dsDesc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
    const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp =
    { D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS };
    dsDesc.FrontFace = defaultStencilOp;
    dsDesc.BackFace = defaultStencilOp;
 
    D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
    psoDesc.InputLayout = inputLayoutDesc;
    psoDesc.pRootSignature = rootSignature;
    psoDesc.VS = vertexShaderBytecode;
    psoDesc.PS = pixelShaderBytecode;
    psoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; 
    psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; 
    psoDesc.SampleDesc.Count = 1;
    psoDesc.SampleMask = 0xffffffff;
    psoDesc.RasterizerState = rasterDesc;
    psoDesc.BlendState = blendDesc;
    psoDesc.NumRenderTargets = 1;
    psoDesc.DepthStencilState = dsDesc;
 
    // create the pso
    if (FAILED(device->CreateGraphicsPipelineState(&psoDesc, IID_PPV_ARGS(&pipelineStateObject))))
    {
        return false;
    }
 
    Vertex vList[] = {
        // front face
        { -0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f },
        { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f },
        { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f },
        { 0.5f,  0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f },
 
        // right side face
        { 0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f },
        { 0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 1.0f, 1.0f },
        { 0.5f, -0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 1.0f },
        { 0.5f,  0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f },
 
        // left side face
        { -0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f },
        { -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f },
        { -0.5f, -0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 1.0f },
        { -0.5f,  0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f },
 
        // back face
        { 0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f },
        { -0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 1.0f, 1.0f },
        { 0.5f, -0.5f,  0.5f, 0.0f, 0.0f, 1.0f, 1.0f },
        { -0.5f,  0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f },
 
        // top face
        { -0.5f,  0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f },
        { 0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 1.0f, 1.0f },
        { 0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f },
        { -0.5f,  0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f },
 
        // bottom face
        { 0.5f, -0.5f,  0.5f, 1.0f, 0.0f, 0.0f, 1.0f },
        { -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 1.0f, 1.0f },
        { 0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f },
        { -0.5f, -0.5f,  0.5f, 0.0f, 1.0f, 0.0f, 1.0f },
    };
 
    int32 vBufferSize = sizeof(vList);
 
    D3D12_HEAP_PROPERTIES heapProps = D3D12_HEAP_PROPERTIES();
    heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
    heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
    heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
    heapProps.CreationNodeMask = 1;
    heapProps.VisibleNodeMask = 1;
 
    D3D12_RESOURCE_DESC bufferResourceDesc = D3D12_RESOURCE_DESC();
    bufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
    bufferResourceDesc.Alignment = 0;
    bufferResourceDesc.Width = vBufferSize;
    bufferResourceDesc.Height = 1;
    bufferResourceDesc.DepthOrArraySize = 1;
    bufferResourceDesc.MipLevels = 1;
    bufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
    bufferResourceDesc.SampleDesc.Count = 1;
    bufferResourceDesc.SampleDesc.Quality = 0;
    bufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    bufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
 
    device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&vertexBuffer));
    vertexBuffer->SetName(L"Vertex Buffer Resource Heap");
 
    ID3D12Resource* vBufferUploadHeap;
    heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
    device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&vBufferUploadHeap));
    vBufferUploadHeap->SetName(L"Vertex Buffer Upload Resource Heap");
 
    D3D12_SUBRESOURCE_DATA vertexData = {};
    vertexData.pData = reinterpret_cast<BYTE*>(vList);
    vertexData.RowPitch = vBufferSize; 
    vertexData.SlicePitch = vBufferSize;
 
    UpdateSubresources(commandList, vertexBuffer, vBufferUploadHeap, 0, 0, 1, &vertexData);
 
    D3D12_RESOURCE_BARRIER barrier = D3D12_RESOURCE_BARRIER();
    barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    barrier.Transition.pResource = vertexBuffer;
    barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
    barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
    barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
    commandList->ResourceBarrier(1, &barrier);
    
    DWORD iList[] = 
    {
        // ffront face
        0, 1, 2, // first triangle
        0, 3, 1, // second triangle
 
        // left face
        4, 5, 6, // first triangle
        4, 7, 5, // second triangle
 
        // right face
        8, 9, 10, // first triangle
        8, 11, 9, // second triangle
 
        // back face
        12, 13, 14, // first triangle
        12, 15, 13, // second triangle
 
        // top face
        16, 17, 18, // first triangle
        16, 19, 17, // second triangle
 
        // bottom face
        20, 21, 22, // first triangle
        20, 23, 21, // second triangle
    };
 
 
    int32 iBufferSize = sizeof(iList);
    numCubeIndices = sizeof(iList) / sizeof(DWORD);
    
 
    D3D12_RESOURCE_DESC indexBufferResourceDesc = D3D12_RESOURCE_DESC();
    indexBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
    indexBufferResourceDesc.Alignment = 0;
    indexBufferResourceDesc.Width = iBufferSize;
    indexBufferResourceDesc.Height = 1;
    indexBufferResourceDesc.DepthOrArraySize = 1;
    indexBufferResourceDesc.MipLevels = 1;
    indexBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
    indexBufferResourceDesc.SampleDesc.Count = 1;
    indexBufferResourceDesc.SampleDesc.Quality = 0;
    indexBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
    indexBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
 
    heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
    device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &indexBufferResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&indexBuffer));
    vertexBuffer->SetName(L"Index Buffer Resource Heap");
 
    ID3D12Resource* iBufferUploadHeap;
    heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
    device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &bufferResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&iBufferUploadHeap));
    vBufferUploadHeap->SetName(L"Index Buffer Upload Resource Heap");
 
    D3D12_SUBRESOURCE_DATA indexData = {};
    indexData.pData = reinterpret_cast<BYTE*>(iList);
    indexData.RowPitch = iBufferSize;
    indexData.SlicePitch = iBufferSize;
 
    UpdateSubresources(commandList, indexBuffer, iBufferUploadHeap, 0, 0, 1, &indexData);
 
    D3D12_RESOURCE_BARRIER indexBufferBarrier = D3D12_RESOURCE_BARRIER();
    indexBufferBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    indexBufferBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    indexBufferBarrier.Transition.pResource = indexBuffer;
    indexBufferBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;
    indexBufferBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;
    indexBufferBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
    commandList->ResourceBarrier(1, &indexBufferBarrier);
 
    D3D12_DESCRIPTOR_HEAP_DESC dsvHeapDesc = {};
    dsvHeapDesc.NumDescriptors = 1;
    dsvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
    dsvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    if (FAILED(device->CreateDescriptorHeap(&dsvHeapDesc, IID_PPV_ARGS(&dsDescriptorHeap))))
    {
        Running = false;
    }
 
    D3D12_DEPTH_STENCIL_VIEW_DESC depthStencilDesc = {};
    depthStencilDesc.Format = DXGI_FORMAT_D32_FLOAT;
    depthStencilDesc.ViewDimension = D3D12_DSV_DIMENSION_TEXTURE2D;
    depthStencilDesc.Flags = D3D12_DSV_FLAG_NONE;
 
    D3D12_CLEAR_VALUE depthOptimizedClearValue = {};
    depthOptimizedClearValue.Format = DXGI_FORMAT_D32_FLOAT;
    depthOptimizedClearValue.DepthStencil.Depth = 1.0f;
    depthOptimizedClearValue.DepthStencil.Stencil = 0;
 
    D3D12_RESOURCE_DESC depthstencilResourceDesc = D3D12_RESOURCE_DESC();
    depthstencilResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
    depthstencilResourceDesc.Alignment = 0;
    depthstencilResourceDesc.Width = Width;
    depthstencilResourceDesc.Height = Height;
    depthstencilResourceDesc.DepthOrArraySize = 1;
    depthstencilResourceDesc.MipLevels = 0;
    depthstencilResourceDesc.Format = DXGI_FORMAT_D32_FLOAT;
    depthstencilResourceDesc.SampleDesc.Count = 1;
    depthstencilResourceDesc.SampleDesc.Quality = 0;
    depthstencilResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;
    depthstencilResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
 
    heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
    device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &depthstencilResourceDesc, D3D12_RESOURCE_STATE_DEPTH_WRITE, &depthOptimizedClearValue, IID_PPV_ARGS(&depthStencilBuffer));
    dsDescriptorHeap->SetName(L"Depth/Stencil Resource Heap");
 
    device->CreateDepthStencilView(depthStencilBuffer, &depthStencilDesc, dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
 
    for (int32 i = 0; i < frameBufferCount; ++i)
    {
        D3D12_RESOURCE_DESC constantBufferResourceDesc = D3D12_RESOURCE_DESC();
        constantBufferResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
        constantBufferResourceDesc.Alignment = 0;
        constantBufferResourceDesc.Width = 1024 * 64;
        constantBufferResourceDesc.Height = 1;
        constantBufferResourceDesc.DepthOrArraySize = 1;
        constantBufferResourceDesc.MipLevels = 1;
        constantBufferResourceDesc.Format = DXGI_FORMAT_UNKNOWN;
        constantBufferResourceDesc.SampleDesc.Count = 1;
        constantBufferResourceDesc.SampleDesc.Quality = 0;
        constantBufferResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
        constantBufferResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE;
 
        heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
        hr = device->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &constantBufferResourceDesc, D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&constantBufferUploadHeaps[i]));
        constantBufferUploadHeaps[i]->SetName(L"Constant Buffer Upload Resource Heap");
 
        ZeroMemory(&cbPerObject, sizeof(cbPerObject));
 
        D3D12_RANGE readRange = D3D12_RANGE();
        readRange.Begin = 0;
        readRange.End = 0;
        hr = constantBufferUploadHeaps[i]->Map(0, &readRange, reinterpret_cast<void**>(&cbvGPUAddress[i]));
        memcpy(cbvGPUAddress[i], &cbPerObject, sizeof(cbPerObject));
        memcpy(cbvGPUAddress[i] + ConstantBufferPerObjectAlignedSize, &cbPerObject, sizeof(cbPerObject));
    }
 
    commandList->Close();
    ID3D12CommandList* ppCommandLists[] = { commandList };
    commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
 
    fenceValue[frameIndex]++;
    hr = commandQueue->Signal(fence[frameIndex], fenceValue[frameIndex]);
    if (FAILED(hr))
    {
        Running = false;
    }
 
    vertexBufferView.BufferLocation = vertexBuffer->GetGPUVirtualAddress();
    vertexBufferView.StrideInBytes = sizeof(Vertex);
    vertexBufferView.SizeInBytes = vBufferSize;
 
    indexBufferView.BufferLocation = indexBuffer->GetGPUVirtualAddress();
    indexBufferView.Format = DXGI_FORMAT_R32_UINT;
    indexBufferView.SizeInBytes = iBufferSize;
 
    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = (FLOAT)Width;
    viewport.Height = (FLOAT)Height;
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;
 
    scissorRect.left = 0;
    scissorRect.top = 0;
    scissorRect.right = (LONG)Width;
    scissorRect.bottom = (LONG)Height;
 
    XMMATRIX tmpMat = XMMatrixPerspectiveFovLH(45.0f*(3.14f / 180.0f), (float)Width / (float)Height, 0.1f, 1000.0f);
    XMStoreFloat4x4(&cameraProjMat, tmpMat);
    cameraPosition = XMFLOAT4(0.0f, 2.0f, -4.0f, 0.0f);
    cameraTarget = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
    cameraUp = XMFLOAT4(0.0f, 1.0f, 0.0f, 0.0f);
 
    XMVECTOR cPos = XMLoadFloat4(&cameraPosition);
    XMVECTOR cTarg = XMLoadFloat4(&cameraTarget);
    XMVECTOR cUp = XMLoadFloat4(&cameraUp);
    tmpMat = XMMatrixLookAtLH(cPos, cTarg, cUp);
    XMStoreFloat4x4(&cameraViewMat, tmpMat);
 
    // first cube
    cube1Position = XMFLOAT4(0.0f, 0.0f, 0.0f, 0.0f);
    XMVECTOR posVec = XMLoadFloat4(&cube1Position);
    tmpMat = XMMatrixTranslationFromVector(posVec);
    XMStoreFloat4x4(&cube1RotMat, XMMatrixIdentity());
    XMStoreFloat4x4(&cube1WorldMat, tmpMat);
 
    // second cube
    cube2PositionOffset = XMFLOAT4(1.5f, 0.0f, 0.0f, 0.0f);
    posVec = XMLoadFloat4(&cube2PositionOffset) + XMLoadFloat4(&cube1Position);
    tmpMat = XMMatrixTranslationFromVector(posVec);
    XMStoreFloat4x4(&cube2RotMat, XMMatrixIdentity());
    XMStoreFloat4x4(&cube2WorldMat, tmpMat);
 
    return true;
}
 
void Update()
{
    XMMATRIX rotXMat = XMMatrixRotationX(0.0001f);
    XMMATRIX rotYMat = XMMatrixRotationY(0.0002f);
    XMMATRIX rotZMat = XMMatrixRotationZ(0.0003f);
    XMMATRIX rotMat = XMLoadFloat4x4(&cube1RotMat) * rotXMat * rotYMat * rotZMat;
    XMStoreFloat4x4(&cube1RotMat, rotMat);
    XMMATRIX translationMat = XMMatrixTranslationFromVector(XMLoadFloat4(&cube1Position));
    XMMATRIX worldMat = rotMat * translationMat;
    XMStoreFloat4x4(&cube1WorldMat, worldMat);
    XMMATRIX viewMat = XMLoadFloat4x4(&cameraViewMat);
    XMMATRIX projMat = XMLoadFloat4x4(&cameraProjMat);
    XMMATRIX wvpMat = XMLoadFloat4x4(&cube1WorldMat) * viewMat * projMat;
    XMMATRIX transposed = XMMatrixTranspose(wvpMat);
    XMStoreFloat4x4(&cbPerObject.wvpMat, transposed);
    memcpy(cbvGPUAddress[frameIndex], &cbPerObject, sizeof(cbPerObject));
    rotXMat = XMMatrixRotationX(0.0003f);
    rotYMat = XMMatrixRotationY(0.0002f);
    rotZMat = XMMatrixRotationZ(0.0001f);
    rotMat = rotZMat * (XMLoadFloat4x4(&cube2RotMat) * (rotXMat * rotYMat));
    XMStoreFloat4x4(&cube2RotMat, rotMat);
 
    XMMATRIX translationOffsetMat = XMMatrixTranslationFromVector(XMLoadFloat4(&cube2PositionOffset));
    XMMATRIX scaleMat = XMMatrixScaling(0.5f, 0.5f, 0.5f);
    worldMat = scaleMat * translationOffsetMat * rotMat * translationMat;
    wvpMat = XMLoadFloat4x4(&cube2WorldMat) * viewMat * projMat;
    transposed = XMMatrixTranspose(wvpMat);
    XMStoreFloat4x4(&cbPerObject.wvpMat, transposed);
    memcpy(cbvGPUAddress[frameIndex] + ConstantBufferPerObjectAlignedSize, &cbPerObject, sizeof(cbPerObject));
    XMStoreFloat4x4(&cube2WorldMat, worldMat);
}
 
void UpdatePipeline()
{
    HRESULT hr;
    WaitForPreviousFrame();
    if (FAILED(commandAllocator[frameIndex]->Reset()))
    {
        Running = false;
    }
 
    hr = commandList->Reset(commandAllocator[frameIndex], pipelineStateObject);
    if (FAILED(hr))
    {
        Running = false;
    }
 
    D3D12_RESOURCE_BARRIER renderTargetsBarrier = D3D12_RESOURCE_BARRIER();
    renderTargetsBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    renderTargetsBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    renderTargetsBarrier.Transition.pResource = renderTargets[frameIndex];
    renderTargetsBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
    renderTargetsBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
    renderTargetsBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
    commandList->ResourceBarrier(1, &renderTargetsBarrier);
 
 
    D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle(rtvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
    rtvHandle.ptr += (int32)frameIndex * rtvDescriptorSize;
 
    D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle(dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
    commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);
 
    const float clearColor[] = { 0.0f, 0.2f, 0.4f, 1.0f };
    commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
    commandList->ClearDepthStencilView(dsDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
    commandList->SetGraphicsRootSignature(rootSignature); 
    commandList->RSSetViewports(1, &viewport);
    commandList->RSSetScissorRects(1, &scissorRect);
    commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
    commandList->IASetVertexBuffers(0, 1, &vertexBufferView);
    commandList->IASetIndexBuffer(&indexBufferView);
    //first cube
    commandList->SetGraphicsRootConstantBufferView(0, constantBufferUploadHeaps[frameIndex]->GetGPUVirtualAddress());
    commandList->DrawIndexedInstanced(numCubeIndices, 1, 0, 0, 0);
    //second cube
    commandList->SetGraphicsRootConstantBufferView(0, constantBufferUploadHeaps[frameIndex]->GetGPUVirtualAddress() + ConstantBufferPerObjectAlignedSize);
    commandList->DrawIndexedInstanced(numCubeIndices, 1, 0, 0, 0);
 
    D3D12_RESOURCE_BARRIER presentBarrier = D3D12_RESOURCE_BARRIER();
    presentBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
    presentBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
    presentBarrier.Transition.pResource = renderTargets[frameIndex];
    presentBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
    presentBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
    presentBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
    commandList->ResourceBarrier(1, &presentBarrier);
 
    hr = commandList->Close();
    if (FAILED(hr))
    {
        Running = false;
    }
}
 
void Render()
{
    UpdatePipeline();
    ID3D12CommandList* ppCommandLists[] = { commandList };
    commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
    auto hr = commandQueue->Signal(fence[frameIndex], fenceValue[frameIndex]);
    if (FAILED(hr))
    {
        Running = false;
    }
 
    hr = swapChain->Present(0, 0);
    if (FAILED(hr))
    {
        Running = false;
    }
}
 
void Cleanup()
{
    for (SIZE_T i = 0; i < frameBufferCount; ++i)
    {
        frameIndex = i;
        WaitForPreviousFrame();
    }
 
    BOOL fs = false;
    if (swapChain->GetFullscreenState(&fs, NULL))
    {
        swapChain->SetFullscreenState(false, NULL);
    }
    
    SAFE_RELEASE(swapChain);
    SAFE_RELEASE(commandQueue);
    SAFE_RELEASE(rtvDescriptorHeap);
    SAFE_RELEASE(commandList);
 
    for (SIZE_T i = 0; i < frameBufferCount; ++i)
    {
        SAFE_RELEASE(renderTargets[i]);
        SAFE_RELEASE(commandAllocator[i]);
        SAFE_RELEASE(fence[i]);
    };
 
    SAFE_RELEASE(pipelineStateObject);
    SAFE_RELEASE(rootSignature);
    SAFE_RELEASE(vertexBuffer);
    SAFE_RELEASE(indexBuffer);
 
    SAFE_RELEASE(depthStencilBuffer);
    SAFE_RELEASE(dsDescriptorHeap);
 
    for (SIZE_T i = 0; i < frameBufferCount; ++i)
    {
        SAFE_RELEASE(constantBufferUploadHeaps[i]);
    };
}
 
void WaitForPreviousFrame()
{
    frameIndex = swapChain->GetCurrentBackBufferIndex();
    if (fence[frameIndex]->GetCompletedValue() < fenceValue[frameIndex])
    {
        auto hr = fence[frameIndex]->SetEventOnCompletion(fenceValue[frameIndex], fenceEvent);
        if (FAILED(hr))
        {
            Running = false;
        }
        WaitForSingleObject(fenceEvent, INFINITE);
    }
    fenceValue[frameIndex]++;
}

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  • Suikzau icon
    03/31/26 10:08:58 PM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.@xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400
     Remove the @ 
  • Zyubi icon
    04/05/26 02:30:02 AM UTC
    text |

    0 B

    |

    0 👍

    /

    0 👎

    Best t33n active cpx link daily updates!
     Copy and paste the link in a new browser tab and then hit enter!
     https://crazyporn.xxx/members/157354/?asgtbndr=1&play=true&spon=adworld&zone=400