diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b7981b..88fcddd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,74 @@ -cmake_minimum_required(VERSION 3.22) +cmake_minimum_required(VERSION 4.0) project(sdl_project) +set(CMAKE_C_STANDARD 23) -set(CMAKE_C_STANDARD 11) +# Include the command that downloads libraries +include(FetchContent) + +# define a function for adding git dependencies +function(include_dependency libName gitURL gitTag) + FetchContent_Declare(${libName} + GIT_REPOSITORY ${gitURL} + GIT_TAG ${gitTag} + GIT_SHALLOW TRUE + GIT_PROGRESS TRUE + ) + FetchContent_MakeAvailable(${libName}) +endfunction() + +# add SDL2 support +find_package(SDL2 QUIET) +if (NOT SDL2_FOUND) + message(STATUS "Getting SDL2 from Github") + include_dependency(SDL2 https://github.com/libsdl-org/SDL.git release-2.30.8) +else() + message(STATUS "Using local SDL2") +endif() + +# add SDL2_image support +find_package(SDL2_image QUIET) +if (NOT SDL2_image_FOUND) + message(STATUS "Getting SDL2_image from Github") + include_dependency(SDL2_image https://github.com/libsdl-org/SDL_image.git release-2.8.2) +else() + message(STATUS "Using local SDL2_image") +endif() + +## add SDL2_gfx support (NO find_package, fetch and add it manually) +#find_package(SDL2_gfx QUIET) +#if (NOT SDL2_gfx) +# message(STATUS "Getting SDL2_gfx from Github") +# include_dependency(SDL2_gfx https://github.com/giroletm/SDL2_gfx.git release-1.0.4) +#else() +# message(STATUS "Using local SDL2_gfx") +#endif() + +# SDL2_gfx (DO NOT use the function for this one) +FetchContent_Declare( + SDL2_gfx + GIT_REPOSITORY https://github.com/giroletm/SDL2_gfx.git + GIT_TAG master +) +FetchContent_MakeAvailable(SDL2_gfx) +message(STATUS "sdl2_gfx_SOURCE_DIR is: ${sdl2_gfx_SOURCE_DIR}") +add_library(SDL2_gfx STATIC + ${sdl2_gfx_SOURCE_DIR}/SDL2_gfxPrimitives.c + ${sdl2_gfx_SOURCE_DIR}/SDL2_rotozoom.c +) + +target_include_directories(SDL2_gfx PUBLIC ${sdl2_gfx_SOURCE_DIR}/sdl2_gfx-src) +target_link_libraries(SDL2_gfx PUBLIC SDL2::SDL2) + +# add SDL2_ttf support +#set(SDL2TTF_VENDORED ON) +#find_package(SDL2_ttf QUIET) +#if (NOT SDL2_ttf_FOUND) +# message(STATUS "Getting SDL2_ttf from Github") +# include_dependency(SDL2_ttf https://github.com/libsdl-org/SDL_ttf.git release-2.22.0) +#else() +# message(STATUS "Using local SDL2_ttf") +#endif() -# Must set the path to the main.cpp, for example: scripts/main.cpp if it is inside a folder add_executable(${PROJECT_NAME} scripts/main.c scripts/array.c scripts/vector.c @@ -14,12 +79,36 @@ add_executable(${PROJECT_NAME} scripts/main.c scripts/texture.c scripts/swap.c scripts/upng.c - scripts/display.c) + scripts/display.c +) -# --- SDL2 SETUP --- -set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) -set(SDL2_PATH "SDL2/x86_64-w64-mingw32") +# Target include directories for non-gfx libs +target_include_directories( + ${PROJECT_NAME} + PUBLIC + ${SDL2_INCLUDE_DIRS} + ${SDL2_IMAGE_INCLUDE_DIRS} +# ${SDL2_TTF_INCLUDE_DIRS} + ${sdl2_gfx_SOURCE_DIR} # Add SDL2_gfx headers directory +) -find_package(SDL2 REQUIRED) -include_directories(${SDL2_INCLUDE_DIR}) -target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY} ${SDL2_IMAGE_LIBRARIES}) \ No newline at end of file +# link all libraries to the project +target_link_libraries( + ${PROJECT_NAME} + PRIVATE + SDL2::SDL2 + SDL2::SDL2main + SDL2_image::SDL2_image +# SDL2_ttf::SDL2_ttf + SDL2_gfx # Link in the SDL2_gfx library we added +) + +if (WIN32) + add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "$" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "$" + #COMMAND "${CMAKE_COMMAND}" -E copy_if_different "$" "$" + VERBATIM + ) +endif() \ No newline at end of file diff --git a/cmake-build-debug/SDL2.dll b/cmake-build-debug/SDL2.dll index 2568859..4eb36c8 100644 Binary files a/cmake-build-debug/SDL2.dll and b/cmake-build-debug/SDL2.dll differ diff --git a/scripts/display.c b/scripts/display.c index 49afbb4..3a054a8 100644 --- a/scripts/display.c +++ b/scripts/display.c @@ -2,7 +2,10 @@ #include "display.h" SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; + uint32_t* color_buffer = NULL; +float* z_buffer = NULL; + SDL_Texture* color_buffer_texture = NULL; int window_width = 800; int window_height = 600; @@ -14,19 +17,19 @@ bool initialize_window(void) { } // Set width and height of the SDL window with the max screen resolution - SDL_DisplayMode display_mode; + /*SDL_DisplayMode display_mode; SDL_GetCurrentDisplayMode(0, &display_mode); window_width = display_mode.w; window_height = display_mode.h; - +*/ // Create a SDL Window window = SDL_CreateWindow( - NULL, + "3D Renderer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, window_width, window_height, - SDL_WINDOW_BORDERLESS + SDL_WINDOW_SHOWN ); if (!window) { fprintf(stderr, "Error creating SDL window.\n"); @@ -104,6 +107,14 @@ void clear_color_buffer(uint32_t color) { } } +void clear_z_buffer() { + for (int y = 0; y < window_height; y++) { + for (int x = 0; x < window_width; x++) { + z_buffer[(window_width * y) + x] = 1.0F; + } + } +} + void destroy_window(void) { SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); diff --git a/scripts/display.h b/scripts/display.h index e4bb7e2..d7eb367 100644 --- a/scripts/display.h +++ b/scripts/display.h @@ -25,6 +25,7 @@ enum render_method { extern SDL_Window* window; extern SDL_Renderer* renderer; extern uint32_t* color_buffer; +extern float* z_buffer; extern SDL_Texture* color_buffer_texture; extern int window_width; extern int window_height; @@ -36,6 +37,7 @@ void draw_line(int x0, int y0, int x1, int y1, uint32_t color); void draw_rect(int x, int y, int width, int height, uint32_t color); void render_color_buffer(void); void clear_color_buffer(uint32_t color); +void clear_z_buffer(); void destroy_window(void); #endif diff --git a/scripts/main.c b/scripts/main.c index e9d85e3..66fd255 100644 --- a/scripts/main.c +++ b/scripts/main.c @@ -33,8 +33,9 @@ void setup(void) { render_method = RENDER_TEXTURED_WIRE; cull_method = CULL_BACKFACE; - // Allocate the required memory in bytes to hold the color buffer + // Allocate the required memory in bytes to hold the color buffer and z buffer color_buffer = (uint32_t*)malloc(sizeof(uint32_t) * window_width * window_height); + z_buffer = (float*)malloc(sizeof(float) * window_width * window_height); // Creating a SDL texture that is used to display the color buffer color_buffer_texture = SDL_CreateTexture( @@ -234,19 +235,6 @@ void update(void) { // Save the projected triangle in the array of triangles to render array_push(triangles_to_render, projected_triangle); } - - // Sort the triangles to render by their avg_depth - int num_triangles = array_length(triangles_to_render); - for (int i = 0; i < num_triangles; i++) { - for (int j = i; j < num_triangles; j++) { - if (triangles_to_render[i].avg_depth < triangles_to_render[j].avg_depth) { - // Swap the triangles positions in the array - triangle_t temp = triangles_to_render[i]; - triangles_to_render[i] = triangles_to_render[j]; - triangles_to_render[j] = temp; - } - } - } } /////////////////////////////////////////////////////////////////////////////// @@ -305,7 +293,9 @@ void render(void) { render_color_buffer(); + clear_color_buffer(0xFF000000); + clear_z_buffer(); SDL_RenderPresent(renderer); } @@ -315,6 +305,7 @@ void render(void) { /////////////////////////////////////////////////////////////////////////////// void free_resources(void) { free(color_buffer); + free(z_buffer); array_free(mesh.faces); array_free(mesh.vertices); upng_free(png_texture); diff --git a/scripts/triangle.c b/scripts/triangle.c index 2684cd6..14d5b66 100644 --- a/scripts/triangle.c +++ b/scripts/triangle.c @@ -208,7 +208,19 @@ void draw_texel( int tex_y = abs((int)(interpolated_v * texture_height)) % texture_height; //tex_x = SDL_clamp(tex_x, 0, texture_width); //tex_y = SDL_clamp(tex_y, 0, texture_height); - draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]); + + int z_pos = (window_width * y) + x; + + // Adjust 1/w so the pixels that are closer to the camera have smaller values + interpolated_reciprocal_w = 1.0 - interpolated_reciprocal_w; + + // only draw pixel if depth value is less than one previously stored in z-buffer + if (interpolated_reciprocal_w < z_buffer[z_pos]) { + draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]); + + // update z-buffer value with the 1/w of this current pixel + z_buffer[z_pos] = interpolated_reciprocal_w; + } } /////////////////////////////////////////////////////////////////////////////// @@ -326,3 +338,4 @@ void draw_textured_triangle( } } } +