Skip to content

Commit

Permalink
Fix glReadPixels (#78)
Browse files Browse the repository at this point in the history
* Fix swapped axes in Image.save

* Swap R/B channels for little-endian systems in glReadPixels
  • Loading branch information
OhadRau authored and bryphe committed Jan 5, 2019
1 parent de04037 commit 371f18c
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
16 changes: 16 additions & 0 deletions src/gl_stubs.js
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,21 @@ function caml_glReadPixels_bytecode(x, y, width, height, vFormat, vType, data) {
}

joo_global_object.gl.readPixels(x, y, width, height, format, type, data);

// If we're on a little-endian system, the R/B channels are swapped
// So let's determine endianness...
var marker = new ArrayBuffer(4);
var u32view = new Uint32Array(marker);
u32view[0] = 0x12345678;
var u8view = new Uint8Array(marker);
if (u8view[0] == 0x78 && type == joo_global_object.gl.UNSIGNED_BYTE) {
// We are little-endian. Onto the swap...
var numChannels = format == joo_global_object.gl.RGBA ? 4 : 3;
for (var i = 0; i < width * height * numChannels; i += numChannels) {
var tmp = data[i];
data[i] = data[i+2];
data[i+2] = tmp;
}
}
}

26 changes: 26 additions & 0 deletions src/gl_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,6 +619,19 @@ extern "C" {

glReadPixels(x, y, width, height, format, type, data);

// If we're on a little-endian system, the R/B channels are swapped
// So let's determine endianness...
unsigned int marker = 0x12345678;
if (*(char *) &marker == 0x78 && type == GL_UNSIGNED_BYTE) {
// We are little-endian. Onto the swap...
int numChannels = format == GL_RGBA ? 4 : 3;
for (int i = 0; i < width * height * numChannels; i += numChannels) {
uint8_t tmp = *((uint8_t *) data + i);
*((uint8_t *) data + i) = *((uint8_t *) data + i + 2);
*((uint8_t *) data + i + 2) = tmp;
}
}

CAMLreturn(Val_unit);
}

Expand All @@ -643,6 +656,19 @@ extern "C" {

glReadPixels(x, y, width, height, format, type, data);

// If we're on a little-endian system, the R/B channels are swapped
// So let's determine endianness...
unsigned int marker = 0x12345678;
if (*(char *) &marker == 0x78 && type == GL_UNSIGNED_BYTE) {
// We are little-endian. Onto the swap...
int numChannels = format == GL_RGBA ? 4 : 3;
for (int i = 0; i < width * height * numChannels; i += numChannels) {
uint8_t tmp = *((uint8_t *) data + i);
*((uint8_t *) data + i) = *((uint8_t *) data + i + 2);
*((uint8_t *) data + i + 2) = tmp;
}
}

CAMLreturn(Val_unit);
}
}
3 changes: 1 addition & 2 deletions src/image_stubs.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ function caml_saveImage(image, path) {
var tga_header = [0, 0, 2, 0, 0, 0,
0, 0, 0, 0, 0, 0];
var bitsPerPixel = 8 * image.numChannels * image.channelSize;
var imageDescriptor = image.numChannels > 3 ? 0x28 : 0x20;
var header = [image.width, image.height, (imageDescriptor << 8) | bitsPerPixel];
var header = [image.width, image.height, bitsPerPixel];

// Copy in all the data to the new buffer
var bufferIndex = 0;
Expand Down
4 changes: 1 addition & 3 deletions src/reglfw_image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ extern "C" {
uint8_t tga_header[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t bitsPerPixel = 8 * image->numChannels * image->channelSize;
// See http://www.paulbourke.net/dataformats/tga/
uint8_t imageDescriptor =
image->numChannels > 3 ? 0x28 : 0x20;
uint16_t header[3] = {
(uint16_t) image->width,
(uint16_t) image->height,
(uint16_t) (((uint16_t) imageDescriptor << 8) | (uint16_t) bitsPerPixel)
(uint16_t) bitsPerPixel // Image descriptor = 0
};

const char *path = String_val(vPath);
Expand Down

0 comments on commit 371f18c

Please sign in to comment.