@@ -99,4 +99,144 @@ namespace Nova {
9999 SDL_ReleaseGPUTransferBuffer (device, tBuf);
100100 SDL_ReleaseGPUTransferBuffer (device, ltBuf);
101101 }
102+
103+ void Renderer::UpdateSkybox (std::shared_ptr<Workspace> workspace) {
104+ std::shared_ptr<Sky> sky = nullptr ;
105+
106+ // Find Sky in Lighting (standard location)
107+ if (auto parent = workspace->GetParent ()) {
108+ for (auto & child : parent->GetChildren ()) {
109+ if (auto lighting = std::dynamic_pointer_cast<Lighting>(child)) {
110+ for (auto & lChild : lighting->GetChildren ()) {
111+ if (auto s = std::dynamic_pointer_cast<Sky>(lChild)) {
112+ sky = s;
113+ break ;
114+ }
115+ }
116+ }
117+ }
118+ }
119+
120+ if (!sky) {
121+ return ;
122+ }
123+
124+ bool changed = false ;
125+ std::string newPaths[6 ] = {
126+ sky->props .SkyboxRt , sky->props .SkyboxLf ,
127+ sky->props .SkyboxUp , sky->props .SkyboxDn ,
128+ sky->props .SkyboxBk , sky->props .SkyboxFt
129+ };
130+
131+ if (currentSkyboxPaths[0 ].empty ()) changed = true ; // Initial load
132+
133+ for (int i = 0 ; i < 6 ; i++) {
134+ if (newPaths[i] != currentSkyboxPaths[i]) {
135+ changed = true ;
136+ break ;
137+ }
138+ }
139+
140+ if (changed) {
141+ SDL_Log (" Skybox changed or initializing..." );
142+ std::vector<std::string> paths;
143+ for (int i = 0 ; i < 6 ; i++) {
144+ currentSkyboxPaths[i] = newPaths[i];
145+ std::string path = newPaths[i];
146+ if (path.starts_with (" rbxasset://textures/sky/" )) {
147+ path = " resources/sky/" + path.substr (24 );
148+ }
149+ paths.push_back (path);
150+ SDL_Log (" Face %d: %s" , i, path.c_str ());
151+ }
152+ LoadSkyboxTexture (paths);
153+ }
154+ }
155+
156+ void Renderer::LoadSkyboxTexture (const std::vector<std::string>& paths) {
157+ if (paths.size () < 6 ) return ;
158+
159+ SDL_Surface* surfaces[6 ];
160+ bool success = true ;
161+ for (int i = 0 ; i < 6 ; i++) {
162+ surfaces[i] = IMG_Load (paths[i].c_str ());
163+ if (!surfaces[i]) {
164+ SDL_Log (" Failed to load skybox texture %s: %s" , paths[i].c_str (), SDL_GetError ());
165+ success = false ;
166+ } else {
167+ SDL_Surface* rgba = SDL_ConvertSurface (surfaces[i], SDL_PIXELFORMAT_RGBA32);
168+ SDL_DestroySurface (surfaces[i]);
169+ surfaces[i] = rgba;
170+ }
171+ }
172+
173+ if (!success) {
174+ SDL_Log (" Skybox loading failed due to missing textures." );
175+ for (int i = 0 ; i < 6 ; i++) if (surfaces[i]) SDL_DestroySurface (surfaces[i]);
176+ return ;
177+ }
178+
179+ if (skyboxTexture) SDL_ReleaseGPUTexture (device, skyboxTexture);
180+
181+ SDL_GPUTextureCreateInfo texInfo = {
182+ .type = SDL_GPU_TEXTURETYPE_CUBE,
183+ .format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM,
184+ .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER,
185+ .width = (uint32_t )surfaces[0 ]->w ,
186+ .height = (uint32_t )surfaces[0 ]->h ,
187+ .layer_count_or_depth = 6 ,
188+ .num_levels = 1
189+ };
190+ skyboxTexture = SDL_CreateGPUTexture (device, &texInfo);
191+
192+ uint32_t layerSize = surfaces[0 ]->w * surfaces[0 ]->h * 4 ;
193+ SDL_GPUTransferBufferCreateInfo ltInfo = { .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, .size = layerSize * 6 };
194+ auto ltBuf = SDL_CreateGPUTransferBuffer (device, <Info);
195+ uint8_t * texData = (uint8_t *)SDL_MapGPUTransferBuffer (device, ltBuf, false );
196+
197+ uint32_t width = (uint32_t )surfaces[0 ]->w ;
198+ uint32_t height = (uint32_t )surfaces[0 ]->h ;
199+
200+ for (int i = 0 ; i < 6 ; i++) {
201+ std::memcpy (texData + (i * layerSize), surfaces[i]->pixels , layerSize);
202+
203+ if (i == 2 || i == 3 ) {
204+ uint32_t * pixels = (uint32_t *)(texData + (i * layerSize));
205+ std::vector<uint32_t > temp (width * height);
206+ std::memcpy (temp.data (), pixels, layerSize);
207+
208+ for (uint32_t y = 0 ; y < height; y++) {
209+ for (uint32_t x = 0 ; x < width; x++) {
210+ uint32_t srcIdx = y * width + x;
211+ uint32_t dstIdx;
212+
213+ if (i == 3 ) { // Bottom: 90 degrees clockwise
214+ dstIdx = x * width + (width - 1 - y);
215+ } else { // Top: 90 degrees counter-clockwise
216+ dstIdx = (width - 1 - x) * width + y;
217+ }
218+
219+ pixels[dstIdx] = temp[srcIdx];
220+ }
221+ }
222+ }
223+
224+ SDL_DestroySurface (surfaces[i]);
225+ }
226+ SDL_UnmapGPUTransferBuffer (device, ltBuf);
227+
228+ auto cmd = SDL_AcquireGPUCommandBuffer (device);
229+ auto copy = SDL_BeginGPUCopyPass (cmd);
230+ for (uint32_t i = 0 ; i < 6 ; i++) {
231+ SDL_GPUTextureTransferInfo texSrc = { ltBuf, layerSize * i };
232+ SDL_GPUTextureRegion texDst = { skyboxTexture, 0 , i, 0 , 0 , 0 , width, height, 1 };
233+ SDL_UploadToGPUTexture (copy, &texSrc, &texDst, false );
234+ }
235+ SDL_EndGPUCopyPass (copy);
236+ auto fence = SDL_SubmitGPUCommandBufferAndAcquireFence (cmd);
237+ SDL_WaitForGPUFences (device, true , &fence, 1 );
238+ SDL_ReleaseGPUFence (device, fence);
239+ SDL_ReleaseGPUTransferBuffer (device, ltBuf);
240+ SDL_Log (" Skybox cubemap created successfully (%dx%d)." , width, height);
241+ }
102242}
0 commit comments