Homebrew Draw pixels code

ground

Well-Known Member
OP
Member
Joined
Mar 22, 2007
Messages
907
Trophies
0
XP
572
Country
Netherlands
hello,

I wanted to create some homebrew for a while now, so i started learning c(++). Now I am at the point where I understand most of it, and i got a good working menu(and the 3ds).

But now i wanted to draw a single pixel on the 3ds bottom screen, and the troubles start, as both the location and color are off. I am using the following code(which i found on several homebrew apps).

void drawpixel(int i)
{
u8* screen;
screen = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL);
char r= 0xff;
char g= 0x00;
char b = 0x00;
int height = 240;
u32 v = (height-1-i+i*height)*3;
screen[v] = b;
screen[v + 1] = g;
screen[v + 2] = r;
}
(I know this code can be much shorter, but i wrote a lot out as i try to solve this problem.

i call this function with a for loop, so it should draw a diagonal line in the screen (starting at 1,1). But Here is where it is getting weird, The first diagonal line starts at 1,1, is yellow. the second line starts halfway down the y as and is blue, the third line starts at a quarter of the x as and is blue too (all lines stop halfway at the x as).

can someone explain what I am missing here(my guess is at the screen getframebuffer, but i cant get what).

thanks in advance.
 

Cyan

GBATemp's lurking knight
Former Staff
Joined
Oct 27, 2002
Messages
23,749
Trophies
4
Age
45
Location
Engine room, learning
XP
15,649
Country
France
If the color is wrong it means you are a byte off.
BBGGRR BBGGRR
0000FF 0000FF what you want
00FFFF 00FFFF what you get (yellow)(doesn't make sense, even if it was shifted you should have 2 bytes at 0x00)
FF0000 FF0000 what you get (blue)

and your position seems wrong:
To make a diagonal, shouldn't it be:
(i*height-height+i) ?

sorry if all this is wrong, just thought about it for 2 mins

edit:
ah, your diagonal is probably not in the same direction I thought, so it's fine.
your code seems good to me.
 
  • Like
Reactions: ground

quarz

New Member
Newbie
Joined
Sep 13, 2009
Messages
4
Trophies
0
XP
135
Country
Gambia, The
Hey there! I'm also just starting to write homebrew for 3DS and i used an old example that doesn't work with newer versions of ctrulib. It was a problem with the initialzation of the framebuffers.

I guess you are using gfxInit(some format, some format, bool) in your main() function. Unless you need that format you should use gfxInitDefault() instead.

Your code works on my end, so your problem should be the format of your framebuffers.
 

ground

Well-Known Member
OP
Member
Joined
Mar 22, 2007
Messages
907
Trophies
0
XP
572
Country
Netherlands
Could you send a screenshot/picture of the result you get, plus the loop that is supposed to draw the line?
sure:
strange.jpg

and the loop(copied the most important functions in case you want to look at it):
void clearrow(int row)
{
for (i = 0; i < 51; i = i + 1)
printf("\x1b[%d;%dH ", i, row);
}

void startselector(int value)
{
menu[0] = menu[0] + value;
if (menu[0] >= 4)
menu[0] = 0;
if (menu[0] <= -1)
menu[0] = 3;
}

void drawpixel(int i)
{
char r = 0xff;
char g = 0x00;
char b = 0x00;
int height = 240;
u32 v = (height-1-i+i*height)*3;
screen[v] = b;
screen[v + 1] = g;
screen[v + 2] = r;
}

void start_single(void)
{
int i;
for (i = 0; i < 100; i = i + 1)
drawpixel(i);
}

void start(void)
{
menu[0] = 0;
menu[1] = 1;
hidScanInput();
kDown = hidKeysDown();
enum Menu{
single=0,multi=1,highscores=2,exit=3
};
drawpicture(0);
printf("\x1b[10;3HSingle Player");
printf("\x1b[12;3HMulti Player");
printf("\x1b[14;3HHighscores");
printf("\x1b[16;3HExit");
printf("\x1b[29;20HVersion: %s",version);
while (true)
{
hidScanInput();
kDown = hidKeysDown();

if (kDown&KEY_DDOWN)
startselector(+1);
if (kDown&KEY_DUP)
startselector(-1);
if (kDown&KEY_A)
{
if (menu[0] == single)
start_single();
if (menu[0] == multi)
start_multi();
if (menu[0] == highscores)
start_highscores();
if (menu[0] == exit)
break;
}
printf("\x1b[18;3H%d %d", menu[0], menu[1]);
if (menu[1] != menu[0])
{
clearrow(1);
if (menu[0] == single)
printf("\x1b[10;1HX ");
if (menu[0] == multi)
printf("\x1b[12;1HX ");
if (menu[0] == highscores)
printf("\x1b[14;1HX ");
if (menu[0] == exit)
printf("\x1b[16;1HX ");
}
if (kDown & KEY_START) break;
menu[1] = menu[0];

}
}]
If the color is wrong it means you are a byte off.
BGRBGR
00F00F what you want
0FF0FF what you get (yellow)(doesn't make sense, even if it was shifted you should have 2 bytes at 0x00)
F00F00 what you get (blue)

and your position seems wrong:
To make a diagonal, shouldn't it be:
(i*height-height+i) ?

sorry if all this is wrong, just thought about it for 2 mins

edit:
ah, your diagonal is probably not in the same direction I thought, so it's fine.
your code seems good to me.
yeah, well you could be right, as i still try to picture the "formula"in my head. i can see why it is heigh-1(so it is all on the screen, and the heigh*width*3 is to find the correct location of the pixel in memory, as it is laid out "flat") en why the *3 is there (for each pixel 1, but if it is RGBRGB shouldn't it be *6?).
 

Cyan

GBATemp's lurking knight
Former Staff
Joined
Oct 27, 2002
Messages
23,749
Trophies
4
Age
45
Location
Engine room, learning
XP
15,649
Country
France
no, it's BBGGRR BBGGRR
I just shortened the code to BGR because I was easier to see the "FF" position, I'll edit my message to prevent confusion.
it's *3 for 3 bytes per pixels

the lines shouldn't be dotted.
You have spaces between each colored pixels like if it's printing 1/3 pixels.
maybe you mixed width and height?

is there a "bottom right" buffer? does that exists?
it looks to me you overflow the left buffer and it continues writing to the second buffer.
but the two buffers are maybe separated by a byte, so the color get shifted.


try removing the "*3" (it shouldn't work, just curious to see the result)
 
  • Like
Reactions: ground

Technicmaster0

Well-Known Member
Member
Joined
Oct 22, 2011
Messages
4,406
Trophies
2
Website
www.flashkarten.tk
XP
3,497
Country
Gambia, The
is there a "bottom right" buffer? does that exists?
it looks to me you overflow the left buffer and it continues writing to the second buffer.
but the two buffers are maybe separated by a byte, so the color get shifted.
No. The bottomscreen uses the left buffer as well.

Maybe you are in the wrong RGB mode: both, the draw and the initialization must be in RGB8 or RGB565.
 

ll0rT

Well-Known Member
Member
Joined
Dec 15, 2014
Messages
137
Trophies
0
Age
28
XP
361
Country
You can use:
Code:
void setPixel(u8 *fb, u16 x, u16 y, u8 red, u8 green, u8 blue) {
    fb[3 * (240 - y + (x - 1) * 240)] = blue;
    fb[3 * (240 - y + (x - 1) * 240) + 1] = green;
    fb[3 * (240 - y + (x - 1) * 240) + 2] = red;
}

setPixel(bottomFb, 1, 1, 255, 0, 0); draws a red pixel on top-left corner.
setPixel(bottomFb, 320, 240, 255, 255, 255); draws a white pixel on bottom-right corner.
You can use it for top screen as well if you use top screen's framebuffer in first argument.
 
  • Like
Reactions: ground and Cyan

ground

Well-Known Member
OP
Member
Joined
Mar 22, 2007
Messages
907
Trophies
0
XP
572
Country
Netherlands
You can use:
Code:
void setPixel(u8 *fb, u16 x, u16 y, u8 red, u8 green, u8 blue) {
    fb[3 * (240 - y + (x - 1) * 240)] = blue;
    fb[3 * (240 - y + (x - 1) * 240) + 1] = green;
    fb[3 * (240 - y + (x - 1) * 240) + 2] = red;
}

setPixel(bottomFb, 1, 1, 255, 0, 0); draws a red pixel on top-left corner.
setPixel(bottomFb, 320, 240, 255, 255, 255); draws a white pixel on bottom-right corner.
You can use it for top screen as well if you use top screen's framebuffer in first argument.
thanks for your reply, but colors and locations are still off(in the same way).
could there be somethign wrong witht his code:
gfxInitDefault();
u8* screen;
screen = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL);
 

ll0rT

Well-Known Member
Member
Joined
Dec 15, 2014
Messages
137
Trophies
0
Age
28
XP
361
Country
thanks for your reply, but colors and locations are still off(in the same way).
could there be somethign wrong witht his code:

There is nothing wrong in that code. The problem might be printf.
Did you use this code?
Code:
consoleInit(GFX_BOTTOM, NULL);
This will make all bottom screen pixel drawings inaccurate and I don't know how to fix this. Use one screen to print texts and other screen to draw pixels.
 
  • Like
Reactions: ground

ground

Well-Known Member
OP
Member
Joined
Mar 22, 2007
Messages
907
Trophies
0
XP
572
Country
Netherlands
There is nothing wrong in that code. The problem might be printf.
Did you use this code?
Code:
consoleInit(GFX_BOTTOM, NULL);
This will make all bottom screen pixel drawings inaccurate and I don't know how to fix this. Use one screen to print texts and other screen to draw pixels.
Yes i used consoleinit(GFX_BOTTOM,NULL), otherwise nothing shows up;
I also used printf a lot. And i want to draw pixels to clear some text out, but not everything, so i guess i am going to "space"that out. that works well but it seems inconvenient.
 

Technicmaster0

Well-Known Member
Member
Joined
Oct 22, 2011
Messages
4,406
Trophies
2
Website
www.flashkarten.tk
XP
3,497
Country
Gambia, The
Yes i used consoleinit(GFX_BOTTOM,NULL), otherwise nothing shows up;
I also used printf a lot. And i want to draw pixels to clear some text out, but not everything, so i guess i am going to "space"that out. that works well but it seems inconvenient.
That's the issue. The "printf" command uses RGB565 while your setPixel method uses RGB8. You need another setPixel command to use both at the same time. Try the following:
Code:
//This works only in RGB565 mode
void drawPixel(u32 x, u32 y, u32 color, u8 *fbAdr)
{
	int idx = (x * 240) + (239 - y);
 
	((u16*)fbAdr)[idx] = (u16)color;
}
But that opens another problem: the colors you use with this must be in RGB565 format, not RGB8. You can use the following method to convert the colors from RGB8 to RGB565 (the method is integrated into ctrulib):
Code:
RGB8_to_565(r,g,b)
 
  • Like
Reactions: ll0rT and ground

ground

Well-Known Member
OP
Member
Joined
Mar 22, 2007
Messages
907
Trophies
0
XP
572
Country
Netherlands
That's the issue. The "printf" command uses RGB565 while your setPixel method uses RGB8. You need another setPixel command to use both at the same time. Try the following:
Code:
//This works only in RGB565 mode
void drawPixel(u32 x, u32 y, u32 color, u8 *fbAdr)
{
int idx = (x * 240) + (239 - y);
 
((u16*)fbAdr)[idx] = (u16)color;
}
But that opens another problem: the colors you use with this must be in RGB565 format, not RGB8. You can use the following method to convert the colors from RGB8 to RGB565 (the method is integrated into ctrulib):
Code:
RGB8_to_565(r,g,b)
yup, this did the trick:D thank you.

the code what i have now:
void drawpixel(u8* screen, u32 x,u32 y,u8 r,u8 g, u8 b)
{
u32 color = RGB8_to_565(r, g, b);
int idx = (x * 240) + (239 - y);
((u16*)screen)[idx] = (u16)color;
}
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: 10 tabs open on chrome and no slow downs suck it low ram ple bs lol