summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-10-08 07:11:53 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-10-08 07:11:53 +0300
commitc4aa47eddd21c51173d4400e44e06f32d2080d2d (patch)
treec7a52379e7d0b182c6b5eb3f641bca1a4e11f430 /src
parent83721b5bed2ed1bef0dc1844314e6ea16eef12fa (diff)
Media: Images not processed until data is complete
Diffstat (limited to 'src')
-rw-r--r--src/media.c53
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
55struct Impl_GmImage { 55struct 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
62void init_GmImage(iGmImage *d, const iBlock *data) { 63void 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
71void deinit_GmImage(iGmImage *d) {
72 deinit_Block(&d->partialData);
73 SDL_DestroyTexture(d->texture);
74 deinit_GmMediaProps_(&d->props);
75}
76
77void 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
83void deinit_GmImage(iGmImage *d) {
84 SDL_DestroyTexture(d->texture);
85 deinit_GmMediaProps_(&d->props);
86} 99}
87 100
88iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) 101iDefineTypeConstructionArgs(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/")) {