Hello,
In this thread, I will gather handy functions that are not present in ctrulib, or functions that are more handy or faster than those present in ctrulib.
"Handy" means that screen coordinates are more logic (i.e. X:0;Y:0 === top-left of the screen; X axis goes right and Y axis goes down).
"Faster" means that the code is optimized, and each function has an "in bounds" version that avoids doing all the tests and the crops.
Let's start with the ones written by Capz, MrJPGames and me.
Feel free to send your own and I'll update the list.
drawPixelInBounds
drawPixel
drawImageInBounds
drawImage
drawImageWithAlphaInBounds
Coming soon:
- drawFullScreenImage (to display images that are exactly 400*240 / 320*240)
- drawImageWithAlpha (like drawImage but with transparency)
- drawImageScaled (to draw zoomed images. 2x 3x 4x etc. Maybe scale down x2, x3, x4 ... too.)
- drawImageScaledWithAlpha
- drawSprite (to display only a part of an image)
- drawSpriteWithAlpha
- drawLine
- drawBox
- drawCircle
PS: you can find a quick tutorial explaining how to use your own images in homebrews here:
https://gbatemp.net/threads/handy-functions-for-your-3ds-homebrews.376679/#post-5221079
In this thread, I will gather handy functions that are not present in ctrulib, or functions that are more handy or faster than those present in ctrulib.
"Handy" means that screen coordinates are more logic (i.e. X:0;Y:0 === top-left of the screen; X axis goes right and Y axis goes down).
"Faster" means that the code is optimized, and each function has an "in bounds" version that avoids doing all the tests and the crops.
Let's start with the ones written by Capz, MrJPGames and me.
Feel free to send your own and I'll update the list.
drawPixelInBounds
Code:
/*
* drawPixelInBounds v.0.0.1
* Draws a pixel on a screen
* The pixel coordinates must be in the bounds of the screen.
* @param fb: framebuffer
* @param x: pixel's X coordinate (0-399 on top screens / 0-319 on bottom screen)
* @param y: pixel's Y coordinate (0-239)
* @param r: red (0-255)
* @param g: green (0-255)
* @param b: blue (0-255)
*/
void drawPixelInBounds(u8* fb, s16 x, s16 y, u8 r, u8 g, u8 b){
u32 pixel_index = 3 * (240 - y - 1 + x * 240);
fb[pixel_index] = b; // blue
fb[pixel_index + 1] = g; // green
fb[pixel_index + 2] = r; // red
}
Code:
/*
* drawPixel v.0.0.1
* Draws a pixel on a screen
* The pixel coordinates can be out of the screen
* @param fb: framebuffer
* @param x: pixel's X coordinate
* @param y: pixel's Y coordinate
* @param r: red (0-255)
* @param g: green (0-255)
* @param b: blue (0-255)
*/
void drawPixel(u8* fb, s16 x, s16 y, u8 r, u8 g, u8 b){
// Set screen width
u16 screen_width;
if(fb == gfxGetFramebuffer(GFX_BOTTOM, 0, NULL, NULL)){
screen_width = 320;
}
else{
screen_width = 400;
}
// out-of-bounds
if(x < 0) return;
if(y < 0) return;
if(x > screen_width) return;
if(y > 239) return;
u32 pixel_index = 3 * ((x + 1) * 240 - y - 1);
fb[pixel_index] = b; // blue
fb[pixel_index + 1] = g; // green
fb[pixel_index + 2] = r; // red
}
Code:
/*
* drawImageInBounds v.0.0.2
* Draws an image on a screen
* The image's bin data needs to be rotated by 90 degrees.
* For example with this web tool: http://localhost/3DShomebrew/tools/image-to-bin.html
* You need to include <string.h>
* The image must be entirely visible on screen
* @param fb: framebuffer
* @param x: pixel's X coordinate (0-399 on top screens / 0-319 on bottom screen)
* @param y: pixel's Y coordinate (0-239)
* @param w: image's width (before rotation)
* @param h: image's height (before rotation)
* @param image: the image's bgr data
*/
void drawImageInBounds(u8* fb, s16 x, s16 y, u16 w, u16 h, const u8* image){
u32 i;
// Loop on all the columns to display
for(i = 0; i < w; i++){
// Copy the whole column from the bin image to the framebuffer
memcpy(
&fb[3 * ((x + i + 1) * 240 - y - h)],
&image[i * h * 3],
h * 3
);
}
}
Code:
/*
* drawImage v.0.0.2
* Draws an image on a screen
* The image's bin data needs to be rotated by 90 degrees.
* For example with this web tool: http://localhost/3DShomebrew/tools/image-to-bin.html
* The image can be partially or totally out of the screen.
* @param fb: framebuffer
* @param x: pixel's X coordinate
* @param y: pixel's Y coordinate
* @param w: image's width (before rotation)
* @param h: image's height (before rotation)
* @param image: the image's bgr data
*/
void drawImage(u8* fb, s16 x, s16 y, u16 w, u16 h, const u8* image){
// Set screen width
u16 screen_width;
if(fb == gfxGetFramebuffer(GFX_BOTTOM, 0, NULL, NULL)){
screen_width = 320;
}
else{
screen_width = 400;
}
// out-of-bounds
if(x + w < 0) return;
if(y + h < 0) return;
if(x > screen_width) return;
if(y > 239) return;
// Overflow
u16 image_x_left = 0; // left X offset (first column to display)
u16 image_x_right = w; // right X offset (last column)
u16 image_y_top = 0; // top Y offset (first line)
u16 image_y_bottom = h; // bottom Y offset (last line)
if(x + w > screen_width){
image_x_right = screen_width - x;
}
if(y + h > 240){
image_y_bottom = 240 - y;
}
if(x < 0){
image_x_left = -x;
x = 0;
}
if(y < 0){
image_y_top = -y;
y = 0;
}
u32 i;
// Loop on the columns to display
for(i = 0; i < image_x_right - image_x_left; i++){
// copy
memcpy(
// on the framebuffer, at the column (x + i) and the line (240 - y - image_y_bottom + image_y_top)
&fb[((x + i + 1) * 240 - y - image_y_bottom + image_y_top) * 3],
// from the image, at the column (image_x_left + i) and the line (image_y_bottom)
&image[((image_x_left + i + 1) * h - image_y_bottom) * 3],
// the number of pixels to display in that column * 3bpp
(image_y_bottom - image_y_top) * 3
);
}
}
Code:
/*
* drawImageWithAlphaInBounds v.0.0.1
* Draws an image containing transparency on a screen
* Alpha blending is used on pixels having 0 < alpha < 255.
* The image's bin data needs to be rotated by 90 degrees.
* For example with this web tool: http://localhost/3DShomebrew/tools/image-to-bin.html
* NB: check the "preserve alpha transparency" option.
* You need to include <string.h>
* The image must be entirely visible on screen
* @param fb: framebuffer
* @param x: pixel's X coordinate (0-399 on top screens / 0-319 on bottom screen)
* @param y: pixel's Y coordinate (0-239)
* @param w: image's width (before rotation)
* @param h: image's height (before rotation)
* @param image: the image's abgr data
*/
void drawImageWithAlphaInBounds(u8* fb, s16 x, s16 y, u16 w, u16 h, const u8* image){
u32 i;
u32 j;
u8 alpha;
u32 fb_index;
u32 image_index;
float alpha_ratio;
// Loop on all the pixels to draw
for(i = 0; i < w; i++){
for(j = 0; j < h; j++){
image_index = (i * h + j) * 4;
alpha = image[image_index];
// If alpha is not zero
if(alpha != 0){
// If alpha is 255, copy the pixels
if(alpha == 255){
fb_index = ((i + x + 1) * 240 - y + j) * 3;
fb[fb_index] = image[image_index + 1];
fb[fb_index + 1] = image[image_index + 2];
fb[fb_index + 2] = image[image_index + 3];
}
// Else, alpha blending
else {
alpha_ratio = alpha / 255.0f;
fb_index = ((i + x + 1) * 240 - y + j) * 3;
fb[fb_index] = fb[fb_index] * (1 - alpha_ratio) + image[image_index + 1] * alpha_ratio;
fb[fb_index + 1] = fb[fb_index + 1] * (1 - alpha_ratio) + image[image_index + 2] * alpha_ratio;
fb[fb_index + 2] = fb[fb_index + 2] * (1 - alpha_ratio) + image[image_index + 3] * alpha_ratio;
}
}
}
}
}
Coming soon:
- drawFullScreenImage (to display images that are exactly 400*240 / 320*240)
- drawImageWithAlpha (like drawImage but with transparency)
- drawImageScaled (to draw zoomed images. 2x 3x 4x etc. Maybe scale down x2, x3, x4 ... too.)
- drawImageScaledWithAlpha
- drawSprite (to display only a part of an image)
- drawSpriteWithAlpha
- drawLine
- drawBox
- drawCircle
PS: you can find a quick tutorial explaining how to use your own images in homebrews here:
https://gbatemp.net/threads/handy-functions-for-your-3ds-homebrews.376679/#post-5221079