| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  | #include "lg-renderer.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdbool.h>
 | 
					
						
							|  |  |  | #include <stdint.h>
 | 
					
						
							|  |  |  | #include <SDL2/SDL.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "debug.h"
 | 
					
						
							|  |  |  | #include "memcpySSE.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct LGR_Basic | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   bool               initialized; | 
					
						
							|  |  |  |   LG_RendererFormat  format; | 
					
						
							|  |  |  |   size_t             texSize; | 
					
						
							|  |  |  |   size_t             dataWidth; | 
					
						
							|  |  |  |   SDL_Renderer     * renderer; | 
					
						
							|  |  |  |   SDL_Texture      * texture; | 
					
						
							| 
									
										
										
										
											2017-12-11 03:47:07 +11:00
										 |  |  |   SDL_Rect           destRect; | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char * lgr_basic_get_name() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return "Basic"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool lgr_basic_initialize(void ** opaque, const LG_RendererParams params, const LG_RendererFormat format) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // create our local storage
 | 
					
						
							|  |  |  |   *opaque = malloc(sizeof(struct LGR_Basic)); | 
					
						
							|  |  |  |   if (!*opaque) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DEBUG_INFO("Failed to allocate %lu bytes", sizeof(struct LGR_Basic)); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   memset(*opaque, 0, sizeof(struct LGR_Basic)); | 
					
						
							|  |  |  |   struct LGR_Basic * this = (struct LGR_Basic *)*opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-11 01:31:52 +11:00
										 |  |  |   this->renderer = SDL_CreateRenderer(params.window, -1, | 
					
						
							|  |  |  |     SDL_RENDERER_ACCELERATED | | 
					
						
							| 
									
										
										
										
											2017-12-13 02:22:47 +11:00
										 |  |  |     SDL_RENDERER_PRESENTVSYNC | 
					
						
							| 
									
										
										
										
											2017-12-11 01:31:52 +11:00
										 |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->renderer) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DEBUG_ERROR("Failed to create renderer"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  |   Uint32 sdlFormat; | 
					
						
							|  |  |  |   switch(format.bpp) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     case 24: | 
					
						
							|  |  |  |       sdlFormat = SDL_PIXELFORMAT_RGB24; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     case 32: | 
					
						
							|  |  |  |       sdlFormat = SDL_PIXELFORMAT_ARGB8888; | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |       DEBUG_ERROR("Unsupported bpp"); | 
					
						
							|  |  |  |       return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // calculate the texture size in bytes
 | 
					
						
							|  |  |  |   this->texSize = format.height * format.pitch; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create the target texture
 | 
					
						
							|  |  |  |   this->texture = SDL_CreateTexture( | 
					
						
							| 
									
										
										
										
											2017-12-11 01:31:52 +11:00
										 |  |  |     this->renderer, | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  |     sdlFormat, | 
					
						
							|  |  |  |     SDL_TEXTUREACCESS_STREAMING, | 
					
						
							|  |  |  |     format.width, | 
					
						
							|  |  |  |     format.height | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!this->texture) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DEBUG_ERROR("SDL_CreateTexture failed"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   memcpy(&this->format, &format, sizeof(LG_RendererFormat)); | 
					
						
							|  |  |  |   this->dataWidth   = this->format.width * (this->format.bpp / 8); | 
					
						
							|  |  |  |   this->initialized = true; | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void lgr_basic_deinitialize(void * opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   struct LGR_Basic * this = (struct LGR_Basic *)opaque; | 
					
						
							|  |  |  |   if (!this) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (this->texture) | 
					
						
							|  |  |  |     SDL_DestroyTexture(this->texture); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-11 01:31:52 +11:00
										 |  |  |   if (this->renderer) | 
					
						
							|  |  |  |     SDL_DestroyRenderer(this->renderer); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  |   free(this); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool lgr_basic_is_compatible(void * opaque, const LG_RendererFormat format) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   const struct LGR_Basic * this = (struct LGR_Basic *)opaque; | 
					
						
							|  |  |  |   if (!this || !this->initialized) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return (memcmp(&this->format, &format, sizeof(LG_RendererFormat)) == 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-11 03:47:07 +11:00
										 |  |  | void lgr_basic_on_resize(void * opaque, const int width, const int height, const LG_RendererRect destRect) | 
					
						
							| 
									
										
										
										
											2017-12-11 03:07:27 +11:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-12-11 03:47:07 +11:00
										 |  |  |   struct LGR_Basic * this = (struct LGR_Basic *)opaque; | 
					
						
							| 
									
										
										
										
											2017-12-11 03:07:27 +11:00
										 |  |  |   if (!this || !this->initialized) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2017-12-11 03:47:07 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |   this->destRect.x = destRect.x; | 
					
						
							|  |  |  |   this->destRect.y = destRect.y; | 
					
						
							|  |  |  |   this->destRect.w = destRect.w; | 
					
						
							|  |  |  |   this->destRect.h = destRect.h; | 
					
						
							| 
									
										
										
										
											2017-12-11 03:07:27 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-11 03:47:07 +11:00
										 |  |  | bool lgr_basic_render(void * opaque, const uint8_t * data, bool resample) | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  | { | 
					
						
							|  |  |  |   struct LGR_Basic * this = (struct LGR_Basic *)opaque; | 
					
						
							|  |  |  |   if (!this || !this->initialized) | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   int       pitch; | 
					
						
							|  |  |  |   uint8_t * dest; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (SDL_LockTexture(this->texture, NULL, (void**)&dest, &pitch) != 0) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     DEBUG_ERROR("Failed to lock the texture for update"); | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (pitch == this->format.pitch) | 
					
						
							|  |  |  |     memcpySSE(dest, data, this->texSize); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     for(unsigned int y = 0; y < this->format.height; ++y) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       memcpySSE(dest, data, this->dataWidth); | 
					
						
							|  |  |  |       dest += pitch; | 
					
						
							|  |  |  |       data += this->format.pitch; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SDL_UnlockTexture(this->texture); | 
					
						
							| 
									
										
										
										
											2017-12-11 03:47:07 +11:00
										 |  |  |   SDL_RenderCopy(this->renderer, this->texture, NULL, &this->destRect); | 
					
						
							| 
									
										
										
										
											2017-12-11 03:07:27 +11:00
										 |  |  |   SDL_RenderPresent(this->renderer); | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const LG_Renderer LGR_Basic = | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   .get_name      = lgr_basic_get_name, | 
					
						
							|  |  |  |   .initialize    = lgr_basic_initialize, | 
					
						
							|  |  |  |   .deinitialize  = lgr_basic_deinitialize, | 
					
						
							|  |  |  |   .is_compatible = lgr_basic_is_compatible, | 
					
						
							| 
									
										
										
										
											2017-12-11 03:07:27 +11:00
										 |  |  |   .on_resize     = lgr_basic_on_resize, | 
					
						
							| 
									
										
										
										
											2017-12-05 20:33:05 +11:00
										 |  |  |   .render        = lgr_basic_render | 
					
						
							|  |  |  | }; |