MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
anonymous_namespace{main.cpp}::SoftwareRenderer Class Reference

Public Member Functions

void begin_frame ()
void begin_frame (bool show_intro)
void draw_block (BlockType type, float x, float y, float z, float half_extent, const mxvk::vec4D &tint)
void draw_block_image (BlockType type, int left, int top, int width, int height)
void draw_digit (int x, int y, int digit, int scale, mxvk::MXCOLOR color)
void draw_mesh (const MeshInstance &instance)
void draw_pause_indicator ()
void draw_rectangle (int left, int top, int width, int height, mxvk::MXCOLOR color)
void draw_solid_cube (float x, float y, float z, float half_extent, mxvk::MXCOLOR color)
void draw_text (TTF_Font *font, const std::string &text, int x, int y, const SDL_Color &color)
void draw_wildcard (float x, float y, float z, float half_extent, const mxvk::vec4D &color)
int height () const
int height () const
void resolve_multisampling ()
void set_view (float yaw, float pitch, float distance)
 SoftwareRenderer (int width, int height)
 SoftwareRenderer (int width, int height, const std::string &data_root, bool enable_warp_fix, bool enable_mipmapping, float mip_bias)
SDL_Surface * surface () const
SDL_Surface * surface () const
int width () const
int width () const

Detailed Description

Definition at line 125 of file main.cpp.

Constructor & Destructor Documentation

◆ SoftwareRenderer() [1/2]

anonymous_namespace{main.cpp}::SoftwareRenderer::SoftwareRenderer ( int width,
int height )
inline

Definition at line 127 of file main.cpp.

128 : frame_width(width),
129 frame_height(height),
130 depth_buffer(static_cast<std::size_t>(width) * static_cast<std::size_t>(height)) {
131 frame_surface.reset(SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32));
132 if (frame_surface == nullptr) {
133 throw mxvk::Exception(std::format("3dmath_pong: failed to create framebuffer: {}", SDL_GetError()));
134 }
135 frame_format = SDL_GetPixelFormatDetails(frame_surface->format);
136 if (frame_format == nullptr) {
137 throw mxvk::Exception(std::format("3dmath_pong: failed to query framebuffer format: {}", SDL_GetError()));
138 }
139 camera_rotation.BuildXYZ(17.0f, -8.0f, 0.0f);
140 }

◆ SoftwareRenderer() [2/2]

anonymous_namespace{main.cpp}::SoftwareRenderer::SoftwareRenderer ( int width,
int height,
const std::string & data_root,
bool enable_warp_fix,
bool enable_mipmapping,
float mip_bias )
inline

Definition at line 343 of file main.cpp.

344 : frame_width(width),
345 frame_height(height),
346 depth_buffer(static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * MSAA_SAMPLE_COUNT),
347 color_buffer(static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * MSAA_SAMPLE_COUNT),
348 background(load_texture(data_root + "/level1.png")),
349 intro(load_texture(data_root + "/intro1.png")),
350 warp_fix_enabled(enable_warp_fix),
351 mipmapping_enabled(enable_mipmapping),
352 mip_level_bias(mip_bias) {
353 frame_surface.reset(SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32));
354 if (!frame_surface) {
355 throw mxvk::Exception(std::format("3dmath_puzzle_drop: failed to create framebuffer: {}", SDL_GetError()));
356 }
357 for (const char *filename : BLOCK_TEXTURE_FILES) {
358 block_textures.push_back(load_texture(data_root + "/" + filename, mipmapping_enabled));
359 }
360 }
Texture load_texture(const std::string &filename, const std::string &asset_path, bool generate_mipmaps)
Definition main.cpp:160
constexpr std::array< const char *, 10 > BLOCK_TEXTURE_FILES
Definition main.cpp:43

Member Function Documentation

◆ begin_frame() [1/2]

void anonymous_namespace{main.cpp}::SoftwareRenderer::begin_frame ( )
inline

Definition at line 154 of file main.cpp.

154 {
155 std::ranges::fill(depth_buffer, std::numeric_limits<float>::infinity());
156 for (int y = 0; y < frame_height; ++y) {
157 const float fraction = static_cast<float>(y) / static_cast<float>(frame_height - 1);
158 const int red = static_cast<int>(4.0f + fraction * 5.0f);
159 const int green = static_cast<int>(10.0f + fraction * 12.0f);
160 const int blue = static_cast<int>(24.0f + fraction * 20.0f);
161 const mxvk::MXCOLOR color = mxvk::MXVK_RGB(red, green, blue);
162 for (int x = 0; x < frame_width; ++x) {
163 put_pixel(x, y, color);
164 }
165 }
166 }
std::uint32_t MXCOLOR
Packed 32-bit color in ARGB byte order.
Definition mxvk_math.h:40
constexpr MXCOLOR MXVK_RGB(int r, int g, int b)
Build an opaque ARGB color from red, green, and blue components.
Definition mxvk_math.h:49

◆ begin_frame() [2/2]

void anonymous_namespace{main.cpp}::SoftwareRenderer::begin_frame ( bool show_intro)
inline

Definition at line 379 of file main.cpp.

379 {
380 std::ranges::fill(depth_buffer, std::numeric_limits<float>::infinity());
381 draw_flat_image(show_intro ? intro : background);
382 if (!show_intro) {
383 fill_translucent_rectangle(0, 0, frame_width, frame_height, mxvk::MXVK_RGB(3, 8, 16), 150);
384 }
385 }

◆ draw_block()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_block ( BlockType type,
float x,
float y,
float z,
float half_extent,
const mxvk::vec4D & tint )
inline

Definition at line 419 of file main.cpp.

419 {
420 draw_cube(&block_textures[static_cast<std::size_t>(texture_index(type))], x, y, z, half_extent, tint);
421 }
int texture_index(BlockType type)
Definition main.cpp:182

◆ draw_block_image()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_block_image ( BlockType type,
int left,
int top,
int width,
int height )
inline

Definition at line 458 of file main.cpp.

458 {
459 if (!is_play_block(type) || width <= 0 || height <= 0) {
460 return;
461 }
462
463 const Texture &texture = block_textures[static_cast<std::size_t>(texture_index(type))];
464 const int first_x = std::clamp(left, 0, frame_width);
465 const int first_y = std::clamp(top, 0, frame_height);
466 const int last_x = std::clamp(left + width, 0, frame_width);
467 const int last_y = std::clamp(top + height, 0, frame_height);
468 for (int y = first_y; y < last_y; ++y) {
469 const int source_y = std::clamp((y - top) * texture.height / height, 0, texture.height - 1);
470 auto *row = static_cast<std::uint8_t *>(frame_surface->pixels) + static_cast<std::size_t>(y * frame_surface->pitch);
471 for (int x = first_x; x < last_x; ++x) {
472 const int source_x = std::clamp((x - left) * texture.width / width, 0, texture.width - 1);
473 const mxvk::MXCOLOR color = texture.pixels[static_cast<std::size_t>(source_y * texture.width + source_x)];
474 blend_pixel(row + static_cast<std::size_t>(x * 4), color);
475 }
476 }
477 }
bool is_play_block(BlockType type)
Definition main.cpp:178

◆ draw_digit()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_digit ( int x,
int y,
int digit,
int scale,
mxvk::MXCOLOR color )
inline

Definition at line 216 of file main.cpp.

216 {
217 static constexpr std::array<std::uint8_t, 10> SEGMENTS = {
218 0b1111110,
219 0b0110000,
220 0b1101101,
221 0b1111001,
222 0b0110011,
223 0b1011011,
224 0b1011111,
225 0b1110000,
226 0b1111111,
227 0b1111011,
228 };
229 const std::uint8_t segments = SEGMENTS[static_cast<std::size_t>(std::clamp(digit, 0, 9))];
230 const auto horizontal = [this, scale, color](int left, int top) {
231 fill_rectangle(left + scale, top, scale * 3, scale, color);
232 };
233 const auto vertical = [this, scale, color](int left, int top) {
234 fill_rectangle(left, top + scale, scale, scale * 3, color);
235 };
236 if ((segments & 0b1000000U) != 0U)
237 horizontal(x, y);
238 if ((segments & 0b0100000U) != 0U)
239 vertical(x + scale * 4, y);
240 if ((segments & 0b0010000U) != 0U)
241 vertical(x + scale * 4, y + scale * 4);
242 if ((segments & 0b0001000U) != 0U)
243 horizontal(x, y + scale * 7);
244 if ((segments & 0b0000100U) != 0U)
245 vertical(x, y + scale * 4);
246 if ((segments & 0b0000010U) != 0U)
247 vertical(x, y);
248 if ((segments & 0b0000001U) != 0U)
249 horizontal(x, y + scale * 3);
250 }

◆ draw_mesh()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_mesh ( const MeshInstance & instance)
inline

Definition at line 168 of file main.cpp.

168 {
169 mxvk::Mat4D object_rotation;
170 object_rotation.BuildXYZ(instance.rotation.x, instance.rotation.y, instance.rotation.z);
171
172 std::vector<mxvk::vec4D> camera_vertices(instance.mesh.vertices.size());
173 std::vector<mxvk::vec4D> projected_vertices(instance.mesh.vertices.size());
174 for (std::size_t index = 0; index < instance.mesh.vertices.size(); ++index) {
175 const mxvk::vec4D &vertex = instance.mesh.vertices[index];
176 mxvk::vec4D transformed(
177 vertex.x * instance.scale.x,
178 vertex.y * instance.scale.y,
179 vertex.z * instance.scale.z,
180 1.0f);
181 transformed = object_rotation.MulVec(transformed);
182 transformed += instance.position;
183 transformed = camera_rotation.MulVec(transformed);
184 transformed.z += CAMERA_DISTANCE;
185 camera_vertices[index] = transformed;
186 projected_vertices[index] = project(transformed);
187 }
188
189 const mxvk::vec4D light_direction = normalized({-0.35f, -0.65f, -1.0f, 0.0f});
190 for (const Triangle &triangle : instance.mesh.triangles) {
191 const mxvk::vec4D &a = camera_vertices[triangle.indices[0]];
192 const mxvk::vec4D &b = camera_vertices[triangle.indices[1]];
193 const mxvk::vec4D &c = camera_vertices[triangle.indices[2]];
194 mxvk::vec4D normal = mxvk::vec4D().Build(a, b).CrossProduct(mxvk::vec4D().Build(a, c));
195 normal.Normalize();
196
197 const mxvk::vec4D center = (a + b + c) * (1.0f / 3.0f);
198 const mxvk::vec4D view_direction(-center.x, -center.y, -center.z, 0.0f);
199 if (normal.DotProduct(view_direction) <= 0.0f) {
200 if (!instance.mesh.two_sided) {
201 continue;
202 }
203 normal = normal * -1.0f;
204 }
205
206 const float diffuse = std::max(0.0f, normal.DotProduct(light_direction));
207 const float intensity = std::clamp(0.32f + diffuse * 0.68f, 0.0f, 1.0f);
208 rasterize_triangle(
209 projected_vertices[triangle.indices[0]],
210 projected_vertices[triangle.indices[1]],
211 projected_vertices[triangle.indices[2]],
212 mxvk::shade_color(instance.color, intensity));
213 }
214 }
void BuildXYZ(float theta_x, float theta_y, float theta_z)
Build an XYZ Euler rotation matrix from angles in degrees.
Definition mxvk_math.h:973
vec4D MulVec(const vec4D &in) const
Transform a homogeneous 4D vector by this matrix.
Definition mxvk_math.h:881
float y
Y coordinate.
Definition mxvk_math.h:422
float x
X coordinate.
Definition mxvk_math.h:419
void Normalize()
Normalize the 3D components in place and reset W to 1.
Definition mxvk_math.h:518
constexpr float DotProduct(const vec4D &v) const
Compute the 3D dot product, ignoring the W component.
Definition mxvk_math.h:503
float z
Z coordinate.
Definition mxvk_math.h:425
constexpr float CAMERA_DISTANCE
Definition main.cpp:36
MXCOLOR shade_color(MXCOLOR color, float intensity)
Scale the RGB channels of a color while preserving alpha.
Definition mxvk_math.h:79

◆ draw_pause_indicator()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_pause_indicator ( )
inline

Definition at line 252 of file main.cpp.

252 {
253 fill_rectangle(frame_width - 17, 8, 3, 12, mxvk::MXVK_RGB(255, 220, 92));
254 fill_rectangle(frame_width - 10, 8, 3, 12, mxvk::MXVK_RGB(255, 220, 92));
255 }

◆ draw_rectangle()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_rectangle ( int left,
int top,
int width,
int height,
mxvk::MXCOLOR color )
inline

Definition at line 445 of file main.cpp.

445 {
446 const int first_x = std::clamp(left, 0, frame_width);
447 const int first_y = std::clamp(top, 0, frame_height);
448 const int last_x = std::clamp(left + width, 0, frame_width);
449 const int last_y = std::clamp(top + height, 0, frame_height);
450 for (int y = first_y; y < last_y; ++y) {
451 auto *row = static_cast<std::uint8_t *>(frame_surface->pixels) + static_cast<std::size_t>(y * frame_surface->pitch);
452 for (int x = first_x; x < last_x; ++x) {
453 write_pixel(row + static_cast<std::size_t>(x * 4), color);
454 }
455 }
456 }

◆ draw_solid_cube()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_solid_cube ( float x,
float y,
float z,
float half_extent,
mxvk::MXCOLOR color )
inline

Definition at line 436 of file main.cpp.

436 {
437 const mxvk::vec4D tint(
438 static_cast<float>(mxvk::color_r(color)) / 255.0f,
439 static_cast<float>(mxvk::color_g(color)) / 255.0f,
440 static_cast<float>(mxvk::color_b(color)) / 255.0f,
441 1.0f);
442 draw_cube(nullptr, x, y, z, half_extent, tint);
443 }
constexpr std::uint8_t color_r(MXCOLOR color)
Extract the red component from a packed ARGB color.
Definition mxvk_math.h:54
constexpr std::uint8_t color_g(MXCOLOR color)
Extract the green component from a packed ARGB color.
Definition mxvk_math.h:59
constexpr std::uint8_t color_b(MXCOLOR color)
Extract the blue component from a packed ARGB color.
Definition mxvk_math.h:64

◆ draw_text()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_text ( TTF_Font * font,
const std::string & text,
int x,
int y,
const SDL_Color & color )
inline

Definition at line 479 of file main.cpp.

479 {
480 if (font == nullptr || text.empty()) {
481 return;
482 }
483
484 SurfacePtr text_surface(TTF_RenderText_Blended(font, text.c_str(), 0, color));
485 if (!text_surface) {
486 return;
487 }
488 SDL_SetSurfaceBlendMode(text_surface.get(), SDL_BLENDMODE_BLEND);
489 const SDL_Rect destination{x, y, text_surface->w, text_surface->h};
490 SDL_BlitSurface(text_surface.get(), nullptr, frame_surface.get(), &destination);
491 }
std::unique_ptr< SDL_Surface, SurfaceDeleter > SurfacePtr
Definition main.cpp:29

◆ draw_wildcard()

void anonymous_namespace{main.cpp}::SoftwareRenderer::draw_wildcard ( float x,
float y,
float z,
float half_extent,
const mxvk::vec4D & color )
inline

Definition at line 423 of file main.cpp.

423 {
424 mxvk::vec4D neon(
425 std::max(color.x, 0.08f),
426 std::max(color.y, 0.08f),
427 std::max(color.z, 0.08f),
428 1.0f);
429 const float brightest_channel = std::max({neon.x, neon.y, neon.z});
430 neon.x /= brightest_channel;
431 neon.y /= brightest_channel;
432 neon.z /= brightest_channel;
433 draw_cube(nullptr, x, y, z, half_extent, neon, true);
434 }

◆ height() [1/2]

int anonymous_namespace{main.cpp}::SoftwareRenderer::height ( ) const
inlinenodiscard

Definition at line 150 of file main.cpp.

150 {
151 return frame_height;
152 }

◆ height() [2/2]

int anonymous_namespace{main.cpp}::SoftwareRenderer::height ( ) const
inlinenodiscard

Definition at line 370 of file main.cpp.

370 {
371 return frame_height;
372 }

◆ resolve_multisampling()

void anonymous_namespace{main.cpp}::SoftwareRenderer::resolve_multisampling ( )
inline

Definition at line 387 of file main.cpp.

387 {
388 for (int y = 0; y < frame_height; ++y) {
389 auto *row = static_cast<std::uint8_t *>(frame_surface->pixels) + static_cast<std::size_t>(y * frame_surface->pitch);
390 for (int x = 0; x < frame_width; ++x) {
391 auto *pixel = row + static_cast<std::size_t>(x * 4);
392 const mxvk::MXCOLOR background_color =
393 (0xFFU << 24U) |
394 (static_cast<mxvk::MXCOLOR>(pixel[0]) << 16U) |
395 (static_cast<mxvk::MXCOLOR>(pixel[1]) << 8U) |
396 static_cast<mxvk::MXCOLOR>(pixel[2]);
397 const std::size_t pixel_index = static_cast<std::size_t>(y * frame_width + x);
398 const std::size_t first_sample = pixel_index * MSAA_SAMPLE_COUNT;
399 std::uint32_t red = 0;
400 std::uint32_t green = 0;
401 std::uint32_t blue = 0;
402 for (std::size_t sample = 0; sample < MSAA_SAMPLE_COUNT; ++sample) {
403 const std::size_t sample_index = first_sample + sample;
404 const mxvk::MXCOLOR color = std::isfinite(depth_buffer[sample_index])
405 ? color_buffer[sample_index]
406 : background_color;
407 red += mxvk::color_r(color);
408 green += mxvk::color_g(color);
409 blue += mxvk::color_b(color);
410 }
411 pixel[0] = static_cast<std::uint8_t>((red + MSAA_SAMPLE_COUNT / 2U) / MSAA_SAMPLE_COUNT);
412 pixel[1] = static_cast<std::uint8_t>((green + MSAA_SAMPLE_COUNT / 2U) / MSAA_SAMPLE_COUNT);
413 pixel[2] = static_cast<std::uint8_t>((blue + MSAA_SAMPLE_COUNT / 2U) / MSAA_SAMPLE_COUNT);
414 pixel[3] = 255;
415 }
416 }
417 }

◆ set_view()

void anonymous_namespace{main.cpp}::SoftwareRenderer::set_view ( float yaw,
float pitch,
float distance )
inline

Definition at line 374 of file main.cpp.

374 {
375 camera_rotation.BuildXYZ(pitch, yaw, 0.0f);
376 camera_distance = distance;
377 }

◆ surface() [1/2]

SDL_Surface * anonymous_namespace{main.cpp}::SoftwareRenderer::surface ( ) const
inlinenodiscard

Definition at line 142 of file main.cpp.

142 {
143 return frame_surface.get();
144 }

◆ surface() [2/2]

SDL_Surface * anonymous_namespace{main.cpp}::SoftwareRenderer::surface ( ) const
inlinenodiscard

Definition at line 362 of file main.cpp.

362 {
363 return frame_surface.get();
364 }

◆ width() [1/2]

int anonymous_namespace{main.cpp}::SoftwareRenderer::width ( ) const
inlinenodiscard

Definition at line 146 of file main.cpp.

146 {
147 return frame_width;
148 }

◆ width() [2/2]

int anonymous_namespace{main.cpp}::SoftwareRenderer::width ( ) const
inlinenodiscard

Definition at line 366 of file main.cpp.

366 {
367 return frame_width;
368 }

The documentation for this class was generated from the following files: