MXVK Vulkan Framework 0.35.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 117 of file main.cpp.

Constructor & Destructor Documentation

◆ SoftwareRenderer() [1/2]

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

Definition at line 119 of file main.cpp.

119 : frame_width(width), frame_height(height), depth_buffer(static_cast<std::size_t>(width) * static_cast<std::size_t>(height)) {
120 frame_surface.reset(SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32));
121 if (frame_surface == nullptr) {
122 throw mxvk::Exception(std::format("3dmath_pong: failed to create framebuffer: {}", SDL_GetError()));
123 }
124 frame_format = SDL_GetPixelFormatDetails(frame_surface->format);
125 if (frame_format == nullptr) {
126 throw mxvk::Exception(std::format("3dmath_pong: failed to query framebuffer format: {}", SDL_GetError()));
127 }
128 camera_rotation.BuildXYZ(17.0f, -8.0f, 0.0f);
129 }

◆ 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 311 of file main.cpp.

311 : frame_width(width), frame_height(height), depth_buffer(static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * MSAA_SAMPLE_COUNT), color_buffer(static_cast<std::size_t>(width) * static_cast<std::size_t>(height) * MSAA_SAMPLE_COUNT), background(load_texture(data_root + "/level1.png")), intro(load_texture(data_root + "/intro1.png")), warp_fix_enabled(enable_warp_fix), mipmapping_enabled(enable_mipmapping), mip_level_bias(mip_bias) {
312 frame_surface.reset(SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32));
313 if (!frame_surface) {
314 throw mxvk::Exception(std::format("3dmath_puzzle_drop: failed to create framebuffer: {}", SDL_GetError()));
315 }
316 for (const char *filename : BLOCK_TEXTURE_FILES) {
317 block_textures.push_back(load_texture(data_root + "/" + filename, mipmapping_enabled));
318 }
319 }
Texture load_texture(const std::string &filename, const std::string &asset_path, bool generate_mipmaps)
Definition main.cpp:135
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 137 of file main.cpp.

137 {
138 std::ranges::fill(depth_buffer, std::numeric_limits<float>::infinity());
139 for (int y = 0; y < frame_height; ++y) {
140 const float fraction = static_cast<float>(y) / static_cast<float>(frame_height - 1);
141 const int red = static_cast<int>(4.0f + fraction * 5.0f);
142 const int green = static_cast<int>(10.0f + fraction * 12.0f);
143 const int blue = static_cast<int>(24.0f + fraction * 20.0f);
144 const mxvk::MXCOLOR color = mxvk::MXVK_RGB(red, green, blue);
145 for (int x = 0; x < frame_width; ++x) {
146 put_pixel(x, y, color);
147 }
148 }
149 }
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 332 of file main.cpp.

332 {
333 std::ranges::fill(depth_buffer, std::numeric_limits<float>::infinity());
334 draw_flat_image(show_intro ? intro : background);
335 if (!show_intro) {
336 fill_translucent_rectangle(0, 0, frame_width, frame_height, mxvk::MXVK_RGB(3, 8, 16), 150);
337 }
338 }

◆ 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 366 of file main.cpp.

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

◆ 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 395 of file main.cpp.

395 {
396 if (!is_play_block(type) || width <= 0 || height <= 0) {
397 return;
398 }
399
400 const Texture &texture = block_textures[static_cast<std::size_t>(texture_index(type))];
401 const int first_x = std::clamp(left, 0, frame_width);
402 const int first_y = std::clamp(top, 0, frame_height);
403 const int last_x = std::clamp(left + width, 0, frame_width);
404 const int last_y = std::clamp(top + height, 0, frame_height);
405 for (int y = first_y; y < last_y; ++y) {
406 const int source_y = std::clamp((y - top) * texture.height / height, 0, texture.height - 1);
407 auto *row = static_cast<std::uint8_t *>(frame_surface->pixels) + static_cast<std::size_t>(y * frame_surface->pitch);
408 for (int x = first_x; x < last_x; ++x) {
409 const int source_x = std::clamp((x - left) * texture.width / width, 0, texture.width - 1);
410 const mxvk::MXCOLOR color = texture.pixels[static_cast<std::size_t>(source_y * texture.width + source_x)];
411 blend_pixel(row + static_cast<std::size_t>(x * 4), color);
412 }
413 }
414 }
bool is_play_block(BlockType type)
Definition main.cpp:176

◆ 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 191 of file main.cpp.

191 {
192 static constexpr std::array<std::uint8_t, 10> SEGMENTS = {
193 0b1111110,
194 0b0110000,
195 0b1101101,
196 0b1111001,
197 0b0110011,
198 0b1011011,
199 0b1011111,
200 0b1110000,
201 0b1111111,
202 0b1111011,
203 };
204 const std::uint8_t segments = SEGMENTS[static_cast<std::size_t>(std::clamp(digit, 0, 9))];
205 const auto horizontal = [this, scale, color](int left, int top) { fill_rectangle(left + scale, top, scale * 3, scale, color); };
206 const auto vertical = [this, scale, color](int left, int top) { fill_rectangle(left, top + scale, scale, scale * 3, color); };
207 if ((segments & 0b1000000U) != 0U)
208 horizontal(x, y);
209 if ((segments & 0b0100000U) != 0U)
210 vertical(x + scale * 4, y);
211 if ((segments & 0b0010000U) != 0U)
212 vertical(x + scale * 4, y + scale * 4);
213 if ((segments & 0b0001000U) != 0U)
214 horizontal(x, y + scale * 7);
215 if ((segments & 0b0000100U) != 0U)
216 vertical(x, y + scale * 4);
217 if ((segments & 0b0000010U) != 0U)
218 vertical(x, y);
219 if ((segments & 0b0000001U) != 0U)
220 horizontal(x, y + scale * 3);
221 }

◆ draw_mesh()

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

Definition at line 151 of file main.cpp.

151 {
152 mxvk::Mat4D object_rotation;
153 object_rotation.BuildXYZ(instance.rotation.x, instance.rotation.y, instance.rotation.z);
154
155 std::vector<mxvk::vec4D> camera_vertices(instance.mesh.vertices.size());
156 std::vector<mxvk::vec4D> projected_vertices(instance.mesh.vertices.size());
157 for (std::size_t index = 0; index < instance.mesh.vertices.size(); ++index) {
158 const mxvk::vec4D &vertex = instance.mesh.vertices[index];
159 mxvk::vec4D transformed(vertex.x * instance.scale.x, vertex.y * instance.scale.y, vertex.z * instance.scale.z, 1.0f);
160 transformed = object_rotation.MulVec(transformed);
161 transformed += instance.position;
162 transformed = camera_rotation.MulVec(transformed);
163 transformed.z += CAMERA_DISTANCE;
164 camera_vertices[index] = transformed;
165 projected_vertices[index] = project(transformed);
166 }
167
168 const mxvk::vec4D light_direction = normalized({-0.35f, -0.65f, -1.0f, 0.0f});
169 for (const Triangle &triangle : instance.mesh.triangles) {
170 const mxvk::vec4D &a = camera_vertices[triangle.indices[0]];
171 const mxvk::vec4D &b = camera_vertices[triangle.indices[1]];
172 const mxvk::vec4D &c = camera_vertices[triangle.indices[2]];
173 mxvk::vec4D normal = mxvk::vec4D().Build(a, b).CrossProduct(mxvk::vec4D().Build(a, c));
174 normal.Normalize();
175
176 const mxvk::vec4D center = (a + b + c) * (1.0f / 3.0f);
177 const mxvk::vec4D view_direction(-center.x, -center.y, -center.z, 0.0f);
178 if (normal.DotProduct(view_direction) <= 0.0f) {
179 if (!instance.mesh.two_sided) {
180 continue;
181 }
182 normal = normal * -1.0f;
183 }
184
185 const float diffuse = std::max(0.0f, normal.DotProduct(light_direction));
186 const float intensity = std::clamp(0.32f + diffuse * 0.68f, 0.0f, 1.0f);
187 rasterize_triangle(projected_vertices[triangle.indices[0]], projected_vertices[triangle.indices[1]], projected_vertices[triangle.indices[2]], mxvk::shade_color(instance.color, intensity));
188 }
189 }
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:859
vec4D MulVec(const vec4D &in) const
Transform a homogeneous 4D vector by this matrix.
Definition mxvk_math.h:771
float y
Y coordinate.
Definition mxvk_math.h:369
float x
X coordinate.
Definition mxvk_math.h:366
void Normalize()
Normalize the 3D components in place and reset W to 1.
Definition mxvk_math.h:447
constexpr float DotProduct(const vec4D &v) const
Compute the 3D dot product, ignoring the W component.
Definition mxvk_math.h:438
float z
Z coordinate.
Definition mxvk_math.h:372
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:69

◆ draw_pause_indicator()

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

Definition at line 223 of file main.cpp.

223 {
224 fill_rectangle(frame_width - 17, 8, 3, 12, mxvk::MXVK_RGB(255, 220, 92));
225 fill_rectangle(frame_width - 10, 8, 3, 12, mxvk::MXVK_RGB(255, 220, 92));
226 }

◆ 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 382 of file main.cpp.

382 {
383 const int first_x = std::clamp(left, 0, frame_width);
384 const int first_y = std::clamp(top, 0, frame_height);
385 const int last_x = std::clamp(left + width, 0, frame_width);
386 const int last_y = std::clamp(top + height, 0, frame_height);
387 for (int y = first_y; y < last_y; ++y) {
388 auto *row = static_cast<std::uint8_t *>(frame_surface->pixels) + static_cast<std::size_t>(y * frame_surface->pitch);
389 for (int x = first_x; x < last_x; ++x) {
390 write_pixel(row + static_cast<std::size_t>(x * 4), color);
391 }
392 }
393 }

◆ 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 377 of file main.cpp.

377 {
378 const mxvk::vec4D tint(static_cast<float>(mxvk::color_r(color)) / 255.0f, static_cast<float>(mxvk::color_g(color)) / 255.0f, static_cast<float>(mxvk::color_b(color)) / 255.0f, 1.0f);
379 draw_cube(nullptr, x, y, z, half_extent, tint);
380 }
constexpr std::uint8_t color_r(MXCOLOR color)
Extract the red component from a packed ARGB color.
Definition mxvk_math.h:52
constexpr std::uint8_t color_g(MXCOLOR color)
Extract the green component from a packed ARGB color.
Definition mxvk_math.h:55
constexpr std::uint8_t color_b(MXCOLOR color)
Extract the blue component from a packed ARGB color.
Definition mxvk_math.h:58

◆ 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 416 of file main.cpp.

416 {
417 if (font == nullptr || text.empty()) {
418 return;
419 }
420
421 SurfacePtr text_surface(TTF_RenderText_Blended(font, text.c_str(), 0, color));
422 if (!text_surface) {
423 return;
424 }
425 SDL_SetSurfaceBlendMode(text_surface.get(), SDL_BLENDMODE_BLEND);
426 const SDL_Rect destination{x, y, text_surface->w, text_surface->h};
427 SDL_BlitSurface(text_surface.get(), nullptr, frame_surface.get(), &destination);
428 }
std::unique_ptr< SDL_Surface, SurfaceDeleter > SurfacePtr
Definition main.cpp:27

◆ 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 368 of file main.cpp.

368 {
369 mxvk::vec4D neon(std::max(color.x, 0.08f), std::max(color.y, 0.08f), std::max(color.z, 0.08f), 1.0f);
370 const float brightest_channel = std::max({neon.x, neon.y, neon.z});
371 neon.x /= brightest_channel;
372 neon.y /= brightest_channel;
373 neon.z /= brightest_channel;
374 draw_cube(nullptr, x, y, z, half_extent, neon, true);
375 }

◆ height() [1/2]

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

Definition at line 135 of file main.cpp.

135{ return frame_height; }

◆ height() [2/2]

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

Definition at line 325 of file main.cpp.

325{ return frame_height; }

◆ resolve_multisampling()

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

Definition at line 340 of file main.cpp.

340 {
341 for (int y = 0; y < frame_height; ++y) {
342 auto *row = static_cast<std::uint8_t *>(frame_surface->pixels) + static_cast<std::size_t>(y * frame_surface->pitch);
343 for (int x = 0; x < frame_width; ++x) {
344 auto *pixel = row + static_cast<std::size_t>(x * 4);
345 const mxvk::MXCOLOR background_color = (0xFFU << 24U) | (static_cast<mxvk::MXCOLOR>(pixel[0]) << 16U) | (static_cast<mxvk::MXCOLOR>(pixel[1]) << 8U) | static_cast<mxvk::MXCOLOR>(pixel[2]);
346 const std::size_t pixel_index = static_cast<std::size_t>(y * frame_width + x);
347 const std::size_t first_sample = pixel_index * MSAA_SAMPLE_COUNT;
348 std::uint32_t red = 0;
349 std::uint32_t green = 0;
350 std::uint32_t blue = 0;
351 for (std::size_t sample = 0; sample < MSAA_SAMPLE_COUNT; ++sample) {
352 const std::size_t sample_index = first_sample + sample;
353 const mxvk::MXCOLOR color = std::isfinite(depth_buffer[sample_index]) ? color_buffer[sample_index] : background_color;
354 red += mxvk::color_r(color);
355 green += mxvk::color_g(color);
356 blue += mxvk::color_b(color);
357 }
358 pixel[0] = static_cast<std::uint8_t>((red + MSAA_SAMPLE_COUNT / 2U) / MSAA_SAMPLE_COUNT);
359 pixel[1] = static_cast<std::uint8_t>((green + MSAA_SAMPLE_COUNT / 2U) / MSAA_SAMPLE_COUNT);
360 pixel[2] = static_cast<std::uint8_t>((blue + MSAA_SAMPLE_COUNT / 2U) / MSAA_SAMPLE_COUNT);
361 pixel[3] = 255;
362 }
363 }
364 }

◆ set_view()

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

Definition at line 327 of file main.cpp.

327 {
328 camera_rotation.BuildXYZ(pitch, yaw, 0.0f);
329 camera_distance = distance;
330 }

◆ surface() [1/2]

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

Definition at line 131 of file main.cpp.

131{ return frame_surface.get(); }

◆ surface() [2/2]

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

Definition at line 321 of file main.cpp.

321{ return frame_surface.get(); }

◆ width() [1/2]

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

Definition at line 133 of file main.cpp.

133{ return frame_width; }

◆ width() [2/2]

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

Definition at line 323 of file main.cpp.

323{ return frame_width; }

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