comparison src/render/SDL_render.c @ 5161:b3ccd1947786

Simplified and improved the process of creating a texture from a surface.
author Sam Lantinga <slouken@libsdl.org>
date Thu, 03 Feb 2011 00:54:29 -0800
parents 657543cc92f9
children 4d39eeaad00b
comparison
equal deleted inserted replaced
5160:657543cc92f9 5161:b3ccd1947786
248 } 248 }
249 return texture; 249 return texture;
250 } 250 }
251 251
252 SDL_Texture * 252 SDL_Texture *
253 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, Uint32 format, SDL_Surface * surface) 253 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
254 { 254 {
255 SDL_Texture *texture; 255 const SDL_PixelFormat *fmt;
256 Uint32 requested_format = format; 256 SDL_bool needAlpha;
257 SDL_PixelFormat *fmt; 257 Uint32 i;
258 Uint32 format;
258 int bpp; 259 int bpp;
259 Uint32 Rmask, Gmask, Bmask, Amask; 260 Uint32 Rmask, Gmask, Bmask, Amask;
261 SDL_Texture *texture;
260 262
261 CHECK_RENDERER_MAGIC(renderer, NULL); 263 CHECK_RENDERER_MAGIC(renderer, NULL);
262 264
263 if (!surface) { 265 if (!surface) {
264 SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); 266 SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
265 return NULL; 267 return NULL;
266 } 268 }
269
270 /* See what the best texture format is */
267 fmt = surface->format; 271 fmt = surface->format;
268 272 if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) {
269 if (format) { 273 needAlpha = SDL_TRUE;
270 if (!SDL_PixelFormatEnumToMasks 274 } else {
271 (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { 275 needAlpha = SDL_FALSE;
272 SDL_SetError("Unknown pixel format"); 276 }
273 return 0; 277 format = renderer->info.texture_formats[0];
274 } 278 for (i = 0; i < renderer->info.num_texture_formats; ++i) {
275 } else { 279 if (SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) {
276 SDL_bool hasColorkey; 280 format = renderer->info.texture_formats[i];
277 SDL_BlendMode blendMode; 281 break;
278 SDL_bool hasBlending; 282 }
279 283 }
280 hasColorkey = (SDL_GetColorKey(surface, NULL) == 0); 284
281 285 if (!SDL_PixelFormatEnumToMasks(format, &bpp,
282 SDL_GetSurfaceBlendMode(surface, &blendMode); 286 &Rmask, &Gmask, &Bmask, &Amask)) {
283 hasBlending = (blendMode == SDL_BLENDMODE_BLEND); 287 SDL_SetError("Unknown pixel format");
284 288 return NULL;
285 if (surface->format->Amask || (!hasColorkey && !hasBlending)) { 289 }
286 Uint32 it; 290
287 int pfmt; 291 texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
288 292 surface->w, surface->h);
289 /* Pixel formats, sorted by best first */
290 static const Uint32 sdl_pformats[] = {
291 SDL_PIXELFORMAT_ARGB8888,
292 SDL_PIXELFORMAT_RGBA8888,
293 SDL_PIXELFORMAT_ABGR8888,
294 SDL_PIXELFORMAT_BGRA8888,
295 SDL_PIXELFORMAT_RGB888,
296 SDL_PIXELFORMAT_BGR888,
297 SDL_PIXELFORMAT_RGB24,
298 SDL_PIXELFORMAT_BGR24,
299 SDL_PIXELFORMAT_RGB565,
300 SDL_PIXELFORMAT_BGR565,
301 SDL_PIXELFORMAT_ARGB1555,
302 SDL_PIXELFORMAT_RGBA5551,
303 SDL_PIXELFORMAT_ABGR1555,
304 SDL_PIXELFORMAT_BGRA5551,
305 SDL_PIXELFORMAT_RGB555,
306 SDL_PIXELFORMAT_BGR555,
307 SDL_PIXELFORMAT_ARGB4444,
308 SDL_PIXELFORMAT_RGBA4444,
309 SDL_PIXELFORMAT_ABGR4444,
310 SDL_PIXELFORMAT_BGRA4444,
311 SDL_PIXELFORMAT_RGB444,
312 SDL_PIXELFORMAT_ARGB2101010,
313 SDL_PIXELFORMAT_RGB332,
314 SDL_PIXELFORMAT_UNKNOWN
315 };
316
317 bpp = fmt->BitsPerPixel;
318 Rmask = fmt->Rmask;
319 Gmask = fmt->Gmask;
320 Bmask = fmt->Bmask;
321 Amask = fmt->Amask;
322
323 format =
324 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
325 if (!format) {
326 SDL_SetError("Unknown pixel format");
327 return 0;
328 }
329
330 /* Search requested format in the supported texture */
331 /* formats by current renderer */
332 for (it = 0; it < renderer->info.num_texture_formats; it++) {
333 if (renderer->info.texture_formats[it] == format) {
334 break;
335 }
336 }
337
338 /* If requested format can't be found, search any best */
339 /* format which renderer provides */
340 if (it == renderer->info.num_texture_formats) {
341 pfmt = 0;
342 for (;;) {
343 if (sdl_pformats[pfmt] == SDL_PIXELFORMAT_UNKNOWN) {
344 break;
345 }
346
347 for (it = 0; it < renderer->info.num_texture_formats;
348 it++) {
349 if (renderer->info.texture_formats[it] ==
350 sdl_pformats[pfmt]) {
351 break;
352 }
353 }
354
355 if (it != renderer->info.num_texture_formats) {
356 /* The best format has been found */
357 break;
358 }
359 pfmt++;
360 }
361
362 /* If any format can't be found, then return an error */
363 if (it == renderer->info.num_texture_formats) {
364 SDL_SetError
365 ("Any of the supported pixel formats can't be found");
366 return 0;
367 }
368
369 /* Convert found pixel format back to color masks */
370 if (SDL_PixelFormatEnumToMasks
371 (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
372 &Bmask, &Amask) != SDL_TRUE) {
373 SDL_SetError("Unknown pixel format");
374 return 0;
375 }
376 }
377 } else {
378 /* Need a format with alpha */
379 Uint32 it;
380 int apfmt;
381
382 /* Pixel formats with alpha, sorted by best first */
383 static const Uint32 sdl_alpha_pformats[] = {
384 SDL_PIXELFORMAT_ARGB8888,
385 SDL_PIXELFORMAT_RGBA8888,
386 SDL_PIXELFORMAT_ABGR8888,
387 SDL_PIXELFORMAT_BGRA8888,
388 SDL_PIXELFORMAT_ARGB1555,
389 SDL_PIXELFORMAT_RGBA5551,
390 SDL_PIXELFORMAT_ABGR1555,
391 SDL_PIXELFORMAT_BGRA5551,
392 SDL_PIXELFORMAT_ARGB4444,
393 SDL_PIXELFORMAT_RGBA4444,
394 SDL_PIXELFORMAT_ABGR4444,
395 SDL_PIXELFORMAT_BGRA4444,
396 SDL_PIXELFORMAT_ARGB2101010,
397 SDL_PIXELFORMAT_UNKNOWN
398 };
399
400 if (surface->format->Amask) {
401 /* If surface already has alpha, then try an original */
402 /* surface format first */
403 bpp = fmt->BitsPerPixel;
404 Rmask = fmt->Rmask;
405 Gmask = fmt->Gmask;
406 Bmask = fmt->Bmask;
407 Amask = fmt->Amask;
408 } else {
409 bpp = 32;
410 Rmask = 0x00FF0000;
411 Gmask = 0x0000FF00;
412 Bmask = 0x000000FF;
413 Amask = 0xFF000000;
414 }
415
416 format =
417 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
418 if (!format) {
419 SDL_SetError("Unknown pixel format");
420 return 0;
421 }
422
423 /* Search this format in the supported texture formats */
424 /* by current renderer */
425 for (it = 0; it < renderer->info.num_texture_formats; it++) {
426 if (renderer->info.texture_formats[it] == format) {
427 break;
428 }
429 }
430
431 /* If this format can't be found, search any best */
432 /* compatible format with alpha which renderer provides */
433 if (it == renderer->info.num_texture_formats) {
434 apfmt = 0;
435 for (;;) {
436 if (sdl_alpha_pformats[apfmt] == SDL_PIXELFORMAT_UNKNOWN) {
437 break;
438 }
439
440 for (it = 0; it < renderer->info.num_texture_formats;
441 it++) {
442 if (renderer->info.texture_formats[it] ==
443 sdl_alpha_pformats[apfmt]) {
444 break;
445 }
446 }
447
448 if (it != renderer->info.num_texture_formats) {
449 /* Compatible format has been found */
450 break;
451 }
452 apfmt++;
453 }
454
455 /* If compatible format can't be found, then return an error */
456 if (it == renderer->info.num_texture_formats) {
457 SDL_SetError("Compatible pixel format can't be found");
458 return 0;
459 }
460
461 /* Convert found pixel format back to color masks */
462 if (SDL_PixelFormatEnumToMasks
463 (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
464 &Bmask, &Amask) != SDL_TRUE) {
465 SDL_SetError("Unknown pixel format");
466 return 0;
467 }
468 }
469 }
470
471 format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
472 if (!format) {
473 SDL_SetError("Unknown pixel format");
474 return 0;
475 }
476 }
477
478 texture =
479 SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
480 surface->w, surface->h);
481 if (!texture && !requested_format) {
482 SDL_DisplayMode desktop_mode;
483 SDL_GetDesktopDisplayMode(&desktop_mode);
484 format = desktop_mode.format;
485 texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
486 surface->w, surface->h);
487 }
488 if (!texture) { 293 if (!texture) {
489 return 0; 294 return NULL;
490 } 295 }
296
491 if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask 297 if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask
492 && Bmask == fmt->Bmask && Amask == fmt->Amask) { 298 && Bmask == fmt->Bmask && Amask == fmt->Amask) {
493 if (SDL_MUSTLOCK(surface)) { 299 if (SDL_MUSTLOCK(surface)) {
494 SDL_LockSurface(surface); 300 SDL_LockSurface(surface);
495 SDL_UpdateTexture(texture, NULL, surface->pixels, 301 SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
496 surface->pitch);
497 SDL_UnlockSurface(surface); 302 SDL_UnlockSurface(surface);
498 } else { 303 } else {
499 SDL_UpdateTexture(texture, NULL, surface->pixels, 304 SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch);
500 surface->pitch);
501 } 305 }
502 } else { 306 } else {
503 SDL_PixelFormat dst_fmt; 307 SDL_PixelFormat dst_fmt;
504 SDL_Surface *dst = NULL; 308 SDL_Surface *temp = NULL;
505 309
506 /* Set up a destination surface for the texture update */ 310 /* Set up a destination surface for the texture update */
507 SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask); 311 SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask);
508 dst = SDL_ConvertSurface(surface, &dst_fmt, 0); 312 temp = SDL_ConvertSurface(surface, &dst_fmt, 0);
509 if (dst) { 313 if (temp) {
510 SDL_UpdateTexture(texture, NULL, dst->pixels, dst->pitch); 314 SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch);
511 SDL_FreeSurface(dst); 315 SDL_FreeSurface(temp);
512 } 316 } else {
513 if (!dst) {
514 SDL_DestroyTexture(texture); 317 SDL_DestroyTexture(texture);
515 return 0; 318 return NULL;
516 } 319 }
517 } 320 }
518 321
519 { 322 {
520 Uint8 r, g, b, a; 323 Uint8 r, g, b, a;