mirror of
https://github.com/ScrelliCopter/NeHe-SDL_GPU.git
synced 2025-06-19 21:49:17 +10:00
c: Add lessons 1-10
This commit is contained in:
266
src/c/lesson6.c
Normal file
266
src/c/lesson6.c
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: (C) 2025 a dinosaur
|
||||
* SPDX-License-Identifier: Zlib
|
||||
*/
|
||||
|
||||
#include "nehe.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float x, y, z;
|
||||
float u, v;
|
||||
} Vertex;
|
||||
|
||||
static const Vertex vertices[] =
|
||||
{
|
||||
// Front Face
|
||||
{ -1.0f, -1.0f, 1.0f, 0.0f, 0.0f },
|
||||
{ 1.0f, -1.0f, 1.0f, 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
{ -1.0f, 1.0f, 1.0f, 0.0f, 1.0f },
|
||||
// Back Face
|
||||
{ -1.0f, -1.0f, -1.0f, 1.0f, 0.0f },
|
||||
{ -1.0f, 1.0f, -1.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, -1.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, -1.0f, -1.0f, 0.0f, 0.0f },
|
||||
// Top Face
|
||||
{ -1.0f, 1.0f, -1.0f, 0.0f, 1.0f },
|
||||
{ -1.0f, 1.0f, 1.0f, 0.0f, 0.0f },
|
||||
{ 1.0f, 1.0f, 1.0f, 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f, -1.0f, 1.0f, 1.0f },
|
||||
// Bottom Face
|
||||
{ -1.0f, -1.0f, -1.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, -1.0f, -1.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, -1.0f, 1.0f, 0.0f, 0.0f },
|
||||
{ -1.0f, -1.0f, 1.0f, 1.0f, 0.0f },
|
||||
// Right face
|
||||
{ 1.0f, -1.0f, -1.0f, 1.0f, 0.0f },
|
||||
{ 1.0f, 1.0f, -1.0f, 1.0f, 1.0f },
|
||||
{ 1.0f, 1.0f, 1.0f, 0.0f, 1.0f },
|
||||
{ 1.0f, -1.0f, 1.0f, 0.0f, 0.0f },
|
||||
// Left Face
|
||||
{ -1.0f, -1.0f, -1.0f, 0.0f, 0.0f },
|
||||
{ -1.0f, -1.0f, 1.0f, 1.0f, 0.0f },
|
||||
{ -1.0f, 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
{ -1.0f, 1.0f, -1.0f, 0.0f, 1.0f }
|
||||
};
|
||||
|
||||
static const uint16_t indices[] =
|
||||
{
|
||||
0, 1, 2, 2, 3, 0, // Front
|
||||
4, 5, 6, 6, 7, 4, // Back
|
||||
8, 9, 10, 10, 11, 8, // Top
|
||||
12, 13, 14, 14, 15, 12, // Bottom
|
||||
16, 17, 18, 18, 19, 16, // Right
|
||||
20, 21, 22, 22, 23, 20 // Left
|
||||
};
|
||||
|
||||
|
||||
static SDL_GPUGraphicsPipeline* pso = NULL;
|
||||
static SDL_GPUBuffer* vtxBuffer = NULL;
|
||||
static SDL_GPUBuffer* idxBuffer = NULL;
|
||||
static SDL_GPUSampler* sampler = NULL;
|
||||
static SDL_GPUTexture* texture = NULL;
|
||||
|
||||
static float projection[16];
|
||||
|
||||
static float xRot = 0.0f, yRot = 0.0f, zRot = 0.0f;
|
||||
|
||||
|
||||
static bool Lesson6_Init(NeHeContext* restrict ctx)
|
||||
{
|
||||
SDL_GPUShader* vertexShader, * fragmentShader;
|
||||
if (!NeHe_LoadShaders(ctx, &vertexShader, &fragmentShader, "lesson6",
|
||||
&(const NeHeShaderProgramCreateInfo){ .vertexUniforms = 1, .fragmentSamplers = 1 }))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const SDL_GPUVertexAttribute vertexAttribs[] =
|
||||
{
|
||||
{
|
||||
.location = 0,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3,
|
||||
.offset = offsetof(Vertex, x)
|
||||
},
|
||||
{
|
||||
.location = 1,
|
||||
.buffer_slot = 0,
|
||||
.format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2,
|
||||
.offset = offsetof(Vertex, u)
|
||||
}
|
||||
};
|
||||
pso = SDL_CreateGPUGraphicsPipeline(ctx->device, &(const SDL_GPUGraphicsPipelineCreateInfo)
|
||||
{
|
||||
.vertex_shader = vertexShader,
|
||||
.fragment_shader = fragmentShader,
|
||||
.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
|
||||
.vertex_input_state =
|
||||
{
|
||||
.vertex_buffer_descriptions = &(const SDL_GPUVertexBufferDescription)
|
||||
{
|
||||
.slot = 0,
|
||||
.pitch = sizeof(Vertex),
|
||||
.input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX
|
||||
},
|
||||
.num_vertex_buffers = 1,
|
||||
.vertex_attributes = vertexAttribs,
|
||||
.num_vertex_attributes = SDL_arraysize(vertexAttribs)
|
||||
},
|
||||
.rasterizer_state =
|
||||
{
|
||||
.fill_mode = SDL_GPU_FILLMODE_FILL,
|
||||
.cull_mode = SDL_GPU_CULLMODE_NONE,
|
||||
.front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE
|
||||
},
|
||||
.depth_stencil_state =
|
||||
{
|
||||
.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL,
|
||||
.enable_depth_test = true,
|
||||
.enable_depth_write = true
|
||||
},
|
||||
.target_info =
|
||||
{
|
||||
.color_target_descriptions = &(const SDL_GPUColorTargetDescription)
|
||||
{
|
||||
.format = SDL_GetGPUSwapchainTextureFormat(ctx->device, ctx->window)
|
||||
},
|
||||
.num_color_targets = 1,
|
||||
.depth_stencil_format = appConfig.createDepthFormat,
|
||||
.has_depth_stencil_target = true
|
||||
}
|
||||
});
|
||||
SDL_ReleaseGPUShader(ctx->device, fragmentShader);
|
||||
SDL_ReleaseGPUShader(ctx->device, vertexShader);
|
||||
if (!pso)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUGraphicsPipeline: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((texture = NeHe_LoadTexture(ctx, "Data/NeHe.bmp", true, false)) == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sampler = SDL_CreateGPUSampler(ctx->device, &(const SDL_GPUSamplerCreateInfo)
|
||||
{
|
||||
.min_filter = SDL_GPU_FILTER_LINEAR,
|
||||
.mag_filter = SDL_GPU_FILTER_LINEAR
|
||||
});
|
||||
if (!sampler)
|
||||
{
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_CreateGPUSampler: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NeHe_CreateVertexIndexBuffer(ctx, &vtxBuffer, &idxBuffer,
|
||||
vertices, sizeof(vertices),
|
||||
indices, sizeof(indices)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Lesson6_Quit(NeHeContext* restrict ctx)
|
||||
{
|
||||
SDL_ReleaseGPUBuffer(ctx->device, idxBuffer);
|
||||
SDL_ReleaseGPUBuffer(ctx->device, vtxBuffer);
|
||||
SDL_ReleaseGPUSampler(ctx->device, sampler);
|
||||
SDL_ReleaseGPUTexture(ctx->device, texture);
|
||||
SDL_ReleaseGPUGraphicsPipeline(ctx->device, pso);
|
||||
}
|
||||
|
||||
static void Lesson6_Resize(NeHeContext* restrict ctx, int width, int height)
|
||||
{
|
||||
(void)ctx;
|
||||
|
||||
// Avoid division by zero by clamping height
|
||||
height = SDL_max(height, 1);
|
||||
// Recalculate projection matrix
|
||||
Mtx_Perspective(projection, 45.0f, (float)width / (float)height, 0.1f, 100.0f);
|
||||
}
|
||||
|
||||
static void Lesson6_Draw(NeHeContext* restrict ctx, SDL_GPUCommandBuffer* restrict cmd, SDL_GPUTexture* restrict swapchain)
|
||||
{
|
||||
const SDL_GPUColorTargetInfo colorInfo =
|
||||
{
|
||||
.texture = swapchain,
|
||||
.clear_color = { 0.0f, 0.0f, 0.0f, 0.5f },
|
||||
.load_op = SDL_GPU_LOADOP_CLEAR,
|
||||
.store_op = SDL_GPU_STOREOP_STORE
|
||||
};
|
||||
|
||||
const SDL_GPUDepthStencilTargetInfo depthInfo =
|
||||
{
|
||||
.texture = ctx->depthTexture,
|
||||
.clear_depth = 1.0f, // Ensure depth buffer clears to furthest value
|
||||
.load_op = SDL_GPU_LOADOP_CLEAR,
|
||||
.store_op = SDL_GPU_STOREOP_DONT_CARE,
|
||||
.stencil_load_op = SDL_GPU_LOADOP_DONT_CARE,
|
||||
.stencil_store_op = SDL_GPU_STOREOP_DONT_CARE,
|
||||
.cycle = true
|
||||
};
|
||||
|
||||
// Begin pass & bind pipeline state
|
||||
SDL_GPURenderPass* pass = SDL_BeginGPURenderPass(cmd, &colorInfo, 1, &depthInfo);
|
||||
SDL_BindGPUGraphicsPipeline(pass, pso);
|
||||
|
||||
// Bind texture
|
||||
SDL_BindGPUFragmentSamplers(pass, 0, &(const SDL_GPUTextureSamplerBinding)
|
||||
{
|
||||
.texture = texture,
|
||||
.sampler = sampler
|
||||
}, 1);
|
||||
|
||||
// Bind vertex & index buffers
|
||||
SDL_BindGPUVertexBuffers(pass, 0, &(const SDL_GPUBufferBinding)
|
||||
{
|
||||
.buffer = vtxBuffer,
|
||||
.offset = 0
|
||||
}, 1);
|
||||
SDL_BindGPUIndexBuffer(pass, &(const SDL_GPUBufferBinding)
|
||||
{
|
||||
.buffer = idxBuffer,
|
||||
.offset = 0
|
||||
}, SDL_GPU_INDEXELEMENTSIZE_16BIT);
|
||||
|
||||
float model[16];
|
||||
struct { float modelViewProj[16], color[4]; } u;
|
||||
|
||||
// Move cube 5 units into the screen and apply some rotations
|
||||
Mtx_Translation(model, 0.0f, 0.0f, -5.0f);
|
||||
Mtx_Rotate(model, xRot, 1.0f, 0.0f, 0.0f);
|
||||
Mtx_Rotate(model, yRot, 0.0f, 1.0f, 0.0f);
|
||||
Mtx_Rotate(model, zRot, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Push shader uniforms
|
||||
Mtx_Multiply(u.modelViewProj, projection, model);
|
||||
SDL_memcpy(u.color, (float[4]){ 1.0f, 1.0f, 1.0f, 1.0f }, sizeof(float) * 4);
|
||||
SDL_PushGPUVertexUniformData(cmd, 0, &u, sizeof(u));
|
||||
|
||||
// Draw textured cube
|
||||
SDL_DrawGPUIndexedPrimitives(pass, SDL_arraysize(indices), 1, 0, 0, 0);
|
||||
|
||||
SDL_EndGPURenderPass(pass);
|
||||
|
||||
xRot += 0.3f;
|
||||
yRot += 0.2f;
|
||||
zRot += 0.4f;
|
||||
}
|
||||
|
||||
|
||||
const struct AppConfig appConfig =
|
||||
{
|
||||
.title = "NeHe's Texture Mapping Tutorial",
|
||||
.width = 640, .height = 480,
|
||||
.createDepthFormat = SDL_GPU_TEXTUREFORMAT_D16_UNORM,
|
||||
.init = Lesson6_Init,
|
||||
.quit = Lesson6_Quit,
|
||||
.resize = Lesson6_Resize,
|
||||
.draw = Lesson6_Draw
|
||||
};
|
||||
Reference in New Issue
Block a user