diff options
Diffstat (limited to 'src/media.c')
-rw-r--r-- | src/media.c | 53 |
1 files changed, 34 insertions, 19 deletions
diff --git a/src/media.c b/src/media.c index ddf5d45f..253893fc 100644 --- a/src/media.c +++ b/src/media.c | |||
@@ -54,14 +54,29 @@ iDeclareType(GmImage) | |||
54 | 54 | ||
55 | struct Impl_GmImage { | 55 | struct Impl_GmImage { |
56 | iGmMediaProps props; | 56 | iGmMediaProps props; |
57 | iInt2 size; | 57 | iBlock partialData; /* cleared when image is converted to texture */ |
58 | size_t numBytes; | 58 | iInt2 size; |
59 | SDL_Texture *texture; | 59 | size_t numBytes; |
60 | SDL_Texture * texture; | ||
60 | }; | 61 | }; |
61 | 62 | ||
62 | void init_GmImage(iGmImage *d, const iBlock *data) { | 63 | void init_GmImage(iGmImage *d, const iBlock *data) { |
63 | init_GmMediaProps_(&d->props); | 64 | init_GmMediaProps_(&d->props); |
64 | d->numBytes = size_Block(data); | 65 | initCopy_Block(&d->partialData, data); |
66 | d->size = zero_I2(); | ||
67 | d->numBytes = 0; | ||
68 | d->texture = NULL; | ||
69 | } | ||
70 | |||
71 | void deinit_GmImage(iGmImage *d) { | ||
72 | deinit_Block(&d->partialData); | ||
73 | SDL_DestroyTexture(d->texture); | ||
74 | deinit_GmMediaProps_(&d->props); | ||
75 | } | ||
76 | |||
77 | void makeTexture_GmImage(iGmImage *d) { | ||
78 | iBlock *data = &d->partialData; | ||
79 | d->numBytes = size_Block(data); | ||
65 | uint8_t *imgData = stbi_load_from_memory( | 80 | uint8_t *imgData = stbi_load_from_memory( |
66 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); | 81 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); |
67 | if (!imgData) { | 82 | if (!imgData) { |
@@ -69,6 +84,8 @@ void init_GmImage(iGmImage *d, const iBlock *data) { | |||
69 | d->texture = NULL; | 84 | d->texture = NULL; |
70 | } | 85 | } |
71 | else { | 86 | else { |
87 | /* TODO: Save some memory by checking if the alpha channel is actually in use. */ | ||
88 | /* TODO: Resize down to min(maximum texture size, window size). */ | ||
72 | SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormatFrom( | 89 | SDL_Surface *surface = SDL_CreateRGBSurfaceWithFormatFrom( |
73 | imgData, d->size.x, d->size.y, 32, d->size.x * 4, SDL_PIXELFORMAT_ABGR8888); | 90 | imgData, d->size.x, d->size.y, 32, d->size.x * 4, SDL_PIXELFORMAT_ABGR8888); |
74 | /* TODO: In multiwindow case, all windows must have the same shared renderer? | 91 | /* TODO: In multiwindow case, all windows must have the same shared renderer? |
@@ -78,11 +95,7 @@ void init_GmImage(iGmImage *d, const iBlock *data) { | |||
78 | SDL_FreeSurface(surface); | 95 | SDL_FreeSurface(surface); |
79 | stbi_image_free(imgData); | 96 | stbi_image_free(imgData); |
80 | } | 97 | } |
81 | } | 98 | clear_Block(data); |
82 | |||
83 | void deinit_GmImage(iGmImage *d) { | ||
84 | SDL_DestroyTexture(d->texture); | ||
85 | deinit_GmMediaProps_(&d->props); | ||
86 | } | 99 | } |
87 | 100 | ||
88 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) | 101 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) |
@@ -144,15 +157,20 @@ void setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBloc | |||
144 | const iBool isPartial = (flags & partialData_MediaFlag) != 0; | 157 | const iBool isPartial = (flags & partialData_MediaFlag) != 0; |
145 | const iBool allowHide = (flags & allowHide_MediaFlag) != 0; | 158 | const iBool allowHide = (flags & allowHide_MediaFlag) != 0; |
146 | const iBool isDeleting = (!mime || !data); | 159 | const iBool isDeleting = (!mime || !data); |
147 | iMediaId existing = findLinkImage_Media(d, linkId); | 160 | iMediaId existing = findLinkImage_Media(d, linkId); |
148 | if (existing) { | 161 | if (existing) { |
162 | iGmImage *img; | ||
149 | if (isDeleting) { | 163 | if (isDeleting) { |
150 | iGmImage *img; | ||
151 | take_PtrArray(&d->images, existing - 1, (void **) &img); | 164 | take_PtrArray(&d->images, existing - 1, (void **) &img); |
152 | delete_GmImage(img); | 165 | delete_GmImage(img); |
153 | } | 166 | } |
154 | else { | 167 | else { |
155 | iAssert(isDeleting); /* images cannot be modified once set */ | 168 | img = at_PtrArray(&d->images, existing - 1); |
169 | iAssert(equal_String(&img->props.mime, mime)); /* MIME cannot change */ | ||
170 | set_Block(&img->partialData, data); | ||
171 | if (!isPartial) { | ||
172 | makeTexture_GmImage(img); | ||
173 | } | ||
156 | } | 174 | } |
157 | } | 175 | } |
158 | else if ((existing = findLinkAudio_Media(d, linkId)) != 0) { | 176 | else if ((existing = findLinkAudio_Media(d, linkId)) != 0) { |
@@ -177,16 +195,13 @@ void setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBloc | |||
177 | else if (!isDeleting) { | 195 | else if (!isDeleting) { |
178 | if (startsWith_String(mime, "image/")) { | 196 | if (startsWith_String(mime, "image/")) { |
179 | /* Copy the image to a texture. */ | 197 | /* Copy the image to a texture. */ |
180 | /* TODO: Resize down to min(maximum texture size, window size). */ | ||
181 | iGmImage *img = new_GmImage(data); | 198 | iGmImage *img = new_GmImage(data); |
182 | img->props.linkId = linkId; /* TODO: use a hash? */ | 199 | img->props.linkId = linkId; /* TODO: use a hash? */ |
183 | img->props.isPermanent = !allowHide; | 200 | img->props.isPermanent = !allowHide; |
184 | set_String(&img->props.mime, mime); | 201 | set_String(&img->props.mime, mime); |
185 | if (img->texture) { | 202 | pushBack_PtrArray(&d->images, img); |
186 | pushBack_PtrArray(&d->images, img); | 203 | if (!isPartial) { |
187 | } | 204 | makeTexture_GmImage(img); |
188 | else { | ||
189 | delete_GmImage(img); | ||
190 | } | 205 | } |
191 | } | 206 | } |
192 | else if (startsWith_String(mime, "audio/")) { | 207 | else if (startsWith_String(mime, "audio/")) { |