{"id":29054981,"url":"https://github.com/screllicopter/nehe-sdl_gpu","last_synced_at":"2026-05-08T00:39:11.454Z","repository":{"id":296634000,"uuid":"991229898","full_name":"ScrelliCopter/NeHe-SDL_GPU","owner":"ScrelliCopter","description":"NeHe Productions legacy (OpenGL) lessons in SDL_GPU (C99, Rust, Swift)","archived":false,"fork":false,"pushed_at":"2025-06-19T11:48:14.000Z","size":482,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-19T12:38:48.557Z","etag":null,"topics":["c","c99","gpu","metal","nehe","rust","sdl","sdl-gpu","sdl3","swift","vulkan"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"zlib","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ScrelliCopter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING.zlib","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-27T10:13:57.000Z","updated_at":"2025-06-19T11:48:17.000Z","dependencies_parsed_at":"2025-06-01T11:49:48.584Z","dependency_job_id":"e22f25b8-31f7-471e-80e5-8e7bf05052ad","html_url":"https://github.com/ScrelliCopter/NeHe-SDL_GPU","commit_stats":null,"previous_names":["screllicopter/nehe-sdl_gpu"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ScrelliCopter/NeHe-SDL_GPU","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScrelliCopter%2FNeHe-SDL_GPU","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScrelliCopter%2FNeHe-SDL_GPU/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScrelliCopter%2FNeHe-SDL_GPU/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScrelliCopter%2FNeHe-SDL_GPU/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ScrelliCopter","download_url":"https://codeload.github.com/ScrelliCopter/NeHe-SDL_GPU/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ScrelliCopter%2FNeHe-SDL_GPU/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262181059,"owners_count":23271319,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c99","gpu","metal","nehe","rust","sdl","sdl-gpu","sdl3","swift","vulkan"],"created_at":"2025-06-27T03:11:35.545Z","updated_at":"2026-05-08T00:39:11.448Z","avatar_url":"https://github.com/ScrelliCopter.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NeHe Legacy Tutorials on SDL_GPU #\n\nRe-implementations of the venerable [NeHe](https://nehe.gamedev.net/) legacy OpenGL\nlessons with SDL3's modern [GPU API](https://wiki.libsdl.org/SDL3/CategoryGPU).\nLessons 1-10 are currently available in several different languages (C99, Rust,\nand Swift)\n\n## Lessons [01 - 05](https://nehe.gamedev.net/tutorial/lessons_01__05/22004/) ##\n\n### Lesson 01: [Creating An ~~OpenGL~~ SDL_GPU Window](https://nehe.gamedev.net/tutorial/creating_an_opengl_window_(win32)/13001/) ###\nThe simplest lesson, covers creating just enough render pass to clear the\nscreen.\n\n### Lesson 02: [Creating Your First Polygon \u0026 Quad](https://nehe.gamedev.net/tutorial/your_first_polygon/13002/) ###\nThe real polygonal \"Hello world\".\nInstead of old-school `glBegin`/`glEnd` calls we store the shapes in static\nvertex \u0026 index buffers, which are much more efficient. We also introduce our\nfirst shader program, which simply applies our combined model-view-projection\nmatrix to the model in the vertex shader and shades the fragments white.\n\n### Lesson 03: [Flat and Smooth Colors](https://nehe.gamedev.net/tutorial/adding_colour/13003/) ###\nIn place of `glColor3f` calls; we add RGBA components to our vertex structure\nand modify our shader program to interpolate colours between vertices and\noutput the result to each fragment.\n\n### Lesson 04: [Rotating A Polygon](https://nehe.gamedev.net/tutorial/rotation/14001/) ###\nWe have already been using a tiny matrix maths library in place of legacy GL's\n`gl*` matrix stack manipulation calls, we're now using `Mtx_Rotate` in place of\n`glRotatef` to apply a little animation to our previously static shapes.\n\n### Lesson 05: [Solid Objects](https://nehe.gamedev.net/tutorial/3d_shapes/10035/) ###\nLike the original, we modify our shapes to fully bring them into the 3rd\ndimension, turning our triangle into a pyramid and our quad into a cube.\n\nThis is also the point we need to add depth testing. In OpenGL this simply\nrequires enabling the `GL_DEPTH_TEST` capability and passing the\n`GL_DEPTH_BUFFER_BIT` flag to `glClear`, however, modern APIs require depth\nbuffer(s) to be manually created and managed by the client application.\nSDL_GPU thankfully handles resource cycling for us but depth texture management\nboilerplate is long \u0026 repetitive enough to justify being factored out into the\nutility library.\n\n## Lessons [06 - 10](https://nehe.gamedev.net/tutorial/lessons_06__10/17010/) ##\n\n### Lesson 06: [Texture Mapping](https://nehe.gamedev.net/tutorial/texture_mapping/12038/) ###\nFinally, we get to texture mapping. The original lesson is split between an\nolder version based around `auxDIBImageLoad` from the long-deprecated\nMicrosoft-only GLaux library, and an updated addendum demonstrating\nreplacing its usage with [SOIL](https://github.com/SpartanJ/SOIL2). Because\nthe textures are in BMP format we can use the SDL built-in `SDL_LoadBMP`,\nwhich lets us take advantage of the vast Surfaces API to flip the image into\nthe orientation the original program expects, as well as handle pixel format\nconversion for us.\n\nWe modify our pipeline and shader program to replace vertex colours with a\ntexture sampler, we can now bind our texture to the render pass and draw a\nbeautiful textured cube.\n\n### Lesson 07: [Texture Filters, Basic Lighting \u0026 Keyboard Control](https://nehe.gamedev.net/tutorial/texture_filters,_lighting_\u0026_keyboard_control/15002/) ###\nThis lesson introduces multiple texture filtering styles, keyboard control for\nrotating the cube, and togglable lighting.\n\nLighting introduces a new shader which implements just enough legacy-style\nGouraud shading to visually match the original, which required adding a few\nmagic constants to the lighting maths. As lighting is a separate shader\nprogram; we create a second pipeline state for it.\n\nOpenGL filtering \u0026 wrap modes are properties of a texture, NeHe chose to\nimplement switching filtering modes by uploading the same texture multiple\ntimes and switching them at runtime. In modern graphics APIs; texture buffers\nand samplers are separate constructs, so we only need to upload one static\ntexture and cycle samplers instead.\n\nThe last sampler enables mip-mapping. The original lesson uses GLU's\n`gluBuild2DMipmaps` call (which can more or less be substituted with\n[`glGenerateMipmap`](https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGenerateMipmap.xhtml)\nin later versions of OpenGL) to programmatically generate mip-map levels at\nstartup. In SDL_GPU we can use\n[`SDL_GenerateMipmapsForGPUTexture`](https://wiki.libsdl.org/SDL3/SDL_GenerateMipmapsForGPUTexture)\nwith `layer_count_or_depth` set to $floor(\\log_2\\max(width,height))+1$ to\nreplicate OpenGL's behaviour.\n\n### Lesson 08: [Blending](https://nehe.gamedev.net/tutorial/blending/16001/) ###\nThis lesson demonstrates use of additive blending on the previous lesson's\ncube.\n\nThe original lesson simply toggles the `GL_BLEND` capability to enable and\ndisable blending. Since we are re-using the lighting setup; we'll need four\npipelines: the existing lit \u0026 unlit shader programs, and lit \u0026 unlit pipelines\nwith depth testing disabled and blending enabled; to cover all possible toggle\nstates.\n\nThe original uses `glColor4f(1, 1, 1, 0.5)` to halve the opacity when blending\nis toggled on, so we extend Lesson 06's basic textured shader to add a colour\ntinting uniform. Note that OpenGL does not apply per-vertex colour to lit faces\nwithout `GL_COLOR_MATERIAL` explicitly enabled, and the original takes\nadvantage of this to only reduce opacity in the unlit blended case; ergo we\ndon't need a tint uniform in the light shader.\n\n### Lesson 09: [Animated Scenes With Blended Textures](https://nehe.gamedev.net/tutorial/moving_bitmaps_in_3d_space/17001/) ###\nThis lesson draws 50 (or 100 in \"twinkle\" mode) star particles with random\ncolours; animated in a pretty concentric spiral.\n\nWith our modern shader-based pipeline we can simplify drawing the stars by\nmoving the quad vertex/index buffers into the shader and only transforming the\ncentre of each particle, the pipeline attributes can then be simplified down to\njust a point and a colour and all stars are drawn with a single instanced draw\ncall. This also makes the star animation code easier to follow while retaining\nidentical behaviour.\n\n### Lesson 10: [Loading And Moving Through A 3D World](https://nehe.gamedev.net/tutorial/loading_and_moving_through_a_3d_world/22003/) ###\nHere it is, the ever infamous 3D world tutorial. Gaze in wonderment at the\nmajesty of Mud.bmp as you explore the caverns of presumably the author's face\nprocessed with dazzling late 90's Photoshop effects, forever embossed in what\nlooks to be some kind of granite texture. Step into the driver's seat with your\ncomputer keyboard as you explore this truly interactive digital Mount Rushmore\nthrough immersive tank controls.\n\nThis lesson loads the 3D environment from a text file as a triangle list, the\nloader logic is almost identical with the only significant difference being the\nusage of a vertex buffer instead of looping over each triangle within\n`glBegin` \u0026 `glEnd`.\n\nThe togglable blending is carried over from the last lesson and lighting is\ndropped, so only two pipeline states are required. \n\n## Lessons [11 - 15](https://nehe.gamedev.net/tutorial/lessons_11__15/28001/) ##\n\n### Lesson 11: [Waving Texture Map (Modifying The Mesh)](https://nehe.gamedev.net/tutorial/flag_effect_(waving_texture)/16002/) ###\nBosco originally created a grid with the z positions filled with a full cycle\nof a sinusoid, and then cycled the z values horizontally every second frame to\nanimate it waving. `glPolygonMode` was used to render the front of the flag as\nsolid and the back as wireframe.\n\nWe generate a flat grid and move flag waving calculations to the vertex shader\nso there's no need to store and modify the z positions on the CPU. Rendering\nthe back of the flag as a *quad* wireframe is not trivially translatable to\nSDL_GPU as while drawing one side as a wireframe could be simply accomplished\nwith drawing the same model twice with two pipelines, modern APIs don't have\nquad primitives so we use separate indices to draw the grid as lines; with the\ndownside that the wireframe grid is always visible no matter the viewing angle.\nIn practice this is not very noticeable because the line grid is drawn with the\nsame texture.\n\n### Lesson 12: [Display Lists](https://nehe.gamedev.net/tutorial/display_lists/15003/) ###\nInstead of old-school display lists, instancing is used. We use attributes for\nper-instance data instead of storage buffers as the D3D12 shader has problems\nwith indexing dynamically into storage buffers, unfortunately this requires\npassing model matrices as 4 separate columns and transposing it in the shader\nfor Vulkan.\n\n### Lesson 13: [Using Bitmap Fonts](https://nehe.gamedev.net/tutorial/bitmap_fonts/17002/) ###\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscrellicopter%2Fnehe-sdl_gpu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fscrellicopter%2Fnehe-sdl_gpu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fscrellicopter%2Fnehe-sdl_gpu/lists"}