Homebrew [Release] Lua Player Plus 3DS (lpp-3ds) - LUA interpreter for 3DS

HexZyle

Pretty Petty Pedant
Member
Joined
Sep 12, 2015
Messages
300
Trophies
0
XP
452
Country
Australia
Thanks for your info, I think I'm going to do that

Just wanna update you guys on the latest revision of my text drawing system, which you may use if you want. Both these are initialized once, after which you use the gpu_drawtext to draw your text.
For this I loaded all the letters into a file "img_font", and then in the first segment, I detail where the left and rightmost borders of each letter are. This particular font, each letter is 3 pixels wide, so the coordinates are 1-3, 5-7, etc. The advantage of the single file system for fonts is that it doesn't take forever to load in all the individual files and I presume is much more efficient on the pagefile.

Code:
glyph_l = {}
glyph_r = {}
glyph_w = {}
function g_init(char, l, r) --this saves to an array the left and right pixels, as well as the width of each character, and the character's string is the index
    glyph_l[char] = l
    glyph_r[char] = r
    glyph_w[char] = r-l+1
end
--glyph_w = {} --precalculate this so it's faster on the text drawing system
g_init('0',1,3)
g_init('1',5,7)
g_init('2',9,11)
g_init('3',13,15)
g_init('4',17,19)
g_init('5',21,23)
g_init('6',25,27)
g_init('7',29,31)
g_init('8',33,35)
g_init('9',37,39)

g_init('A',41,43)
g_init('B',45,47)
g_init('C',49,51)
g_init('D',53,55)
g_init('E',57,59)
g_init('F',61,63)
g_init('G',65,67)
g_init('H',69,71)
g_init('I',73,75)
g_init('J',77,79)
g_init('K',81,83)
g_init('L',85,87)
g_init('M',89,95)
g_init('N',97,99)
g_init('O',101,103)
g_init('P',105,107)
g_init('Q',109,111)
g_init('R',113,115)
g_init('S',117,119)
g_init('T',121,123)
g_init('U',125,127)
g_init('V',129,131)
g_init('W',133,139)
g_init('X',141,143)
g_init('Y',145,147)
g_init('Z',149,151)

g_init("'",153,155)
g_init('*',157,159)
g_init(':',161,163)
g_init('[',165,167)
g_init(']',169,171)
g_init('(',173,175)
g_init(')',177,179)
g_init('=',181,183)
g_init('!',185,187)
g_init('/',189,191)
--glyph_l[string.char(0x08)],glyph_r[string.char(0x08)] = 193,195
g_init('>',197,199)
g_init('<',201,203)
g_init('-',205,207)
g_init('%',209,211)
g_init('.',213,215)
g_init('|',217,219)
g_init('+',221,223)
g_init('^',225,227)
g_init('?',229,231)
g_init('"',233,235)
g_init('_',237,239)
g_init(',',241,243)
g_init(';',245,247)
g_init(' ',249,251)

This load in for all the characters is only done once on my system since I only use uppercase. You'd need to do this for all lowercase letters too if you were using them.

Code:
--remember to blend the gpu to what screen you want before calling this function, and termblend afterwards
function gpu_drawtext(x, y, text, font_color)
    local text_u = string.upper(text) --my font system is caps-only.
    local i_str=0 --the current position in the string
    local i_chr='' --the current character in the string
    local str_width = 0 --width in pixels of the string
    local str_length = string.len(text)
    local cw --character width
    while i_str < str_length do
        i_str = i_str + 1
        i_chr = string.sub(text_u, i_str, i_str)
        cw = glyph_w[i_chr]
        if cw ~= nil then --as long as the character exists
            Graphics.drawPartialImage(x+str_width, y, glyph_l[i_chr], 1, cw, 5, img_font, font_color)
            str_width = str_width + cw + 1
        end
    end
end
 
  • Like
Reactions: Rinnegatamante

The_Marcster

Well-Known Member
Newcomer
Joined
Aug 18, 2015
Messages
98
Trophies
0
Age
24
XP
86
Country
Gambia, The
Well now I might as well share my solution. My solution uses single images for all chars (as I couldn't get Graphics.drawPartialImage to work with large textures) which may be slower on startup, but is very user friendly to use.

Here is the code for the ImageFont module:
Code:
ImageFont = {}
function ImageFont.load(path, baseHeight)
    local imageFont = {}
    imageFont.chars = {}
    for k, v in pairs(System.listDirectory(path)) do
        imageFont.chars[string.char(v['name']:sub(1, -5))] = Graphics.loadImage(path .. v['name'])
    end
    imageFont.baseHeight = baseHeight
    imageFont.height = baseHeight
    return imageFont
end
function ImageFont.setPixelSizes(imageFont, height)
    imageFont.height = height
end
function ImageFont.print(imageFont, x, y, text, color)
    local offset = x
    color = color or Color.new(0, 0, 0)
    for i = 1, #text do
        if(text:sub(i, i) == ' ') then
            offset = math.floor(offset + imageFont.height / 4 + 0.5)
        else
            Graphics.drawScaleImage(offset, y, imageFont.chars[text:sub(i, i)], imageFont.height / imageFont.baseHeight, imageFont.height / imageFont.baseHeight, color)
            offset = math.floor(offset + Graphics.getImageWidth(imageFont.chars[text:sub(i, i)]) * 0.9 * imageFont.height / imageFont.baseHeight + math.ceil(imageFont.height / 36) + 0.5)
        end
    end
end
function ImageFont.unload(imageFont)
    for k, v in pairs(imageFont.chars) do
        Graphics.freeImage(v)
    end
end

As you can see, the module works exactly like the base Font module. The only difference is the ImageFont.load method and the fact that ImageFont.print has to be called during GPU rendering.

The path in you have to provide in ImageFont.load should be a path to a directory (like System.currentDirectory() .. 'fonts/exampleFont/') while baseHeight is the pixel size you used when creating the font (for example 12) so the font can be scaled correctly. I would strongly advise to not use the scaling methods as they leave weird artifacts and weird pixels in places where they don't belong.

The directory has to contain any number of png images called **(*).png where **(*) is the ASCII code for the char. If somebody is interested, I could share a few tools by me that convert a ttf font to an image font.

Also while this module should theoretically work fine, it is not completely bugtested and may crash when you do stuff that's not intended.

I hope this will be useful for some people :)
 

ElyosOfTheAbyss

Well-Known Member
Member
Joined
Aug 20, 2015
Messages
2,225
Trophies
1
XP
1,901
Country
currentDrectory always returns a slash terminated directory so you should remove the "/" before test.lua.
Oh okay, thank you that helped.

Now if anyone knows whats wrong I tried making it load an image but when I load LPP I get a few pixels on the bottom left corner of the screen but if I remove the bitmap part it loads just fine.
This is what I have:

Code:
Menu = Screen.loadImage(System.currentDirectory().."Menu.bmp")

Screen.drawImage(100,127,Menu,TOP_SCREEN)

if Network.isWifiEnabled() then

        -- Download a file
        Network.downloadFile("RemovedLink","/Downloaded.zip")

        -- Extract the file
        System.extractZIP("/Downloaded.zip",System.currentDirectory().."/")

       -- Delete the temp file
       System.deleteFile("/Downloaded.zip")

     dofile(System.currentDirectory().."Script.lua")
end
 

Rinnegatamante

Well-Known Member
OP
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Oh okay, thank you that helped.

Now if anyone knows whats wrong I tried making it load an image but when I load LPP I get a few pixels on the bottom left corner of the screen but if I remove the bitmap part it loads just fine.
This is what I have:

Code:
Menu = Screen.loadImage(System.currentDirectory().."Menu.bmp")

Screen.drawImage(100,127,Menu,TOP_SCREEN)

if Network.isWifiEnabled() then

        -- Download a file
        Network.downloadFile("RemovedLink","/Downloaded.zip")

        -- Extract the file
        System.extractZIP("/Downloaded.zip",System.currentDirectory().."/")

       -- Delete the temp file
       System.deleteFile("/Downloaded.zip")

     dofile(System.currentDirectory().."Script.lua")
end

Is your image small enough to fit the screen? With CPU Rendering you can't go out of bounds from framebuffer. (In that case you must use GPU rendering aka Graphics module).
 

ElyosOfTheAbyss

Well-Known Member
Member
Joined
Aug 20, 2015
Messages
2,225
Trophies
1
XP
1,901
Country
What do you mean exactly by blending it at 0,0 coordinates
I just tried setting the coordinates to 0,0 and it still gives me these weird pixels when starting LPP and it doesnt do anything, just sits here
IMG_0582.JPG
 

Rinnegatamante

Well-Known Member
OP
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
What do you mean exactly by blending it at 0,0 coordinates
I just tried setting the coordinates to 0,0 and it still gives me these weird pixels when starting LPP and it doesnt do anything, just sits here
IMG_0582.JPG

Are you calling waitVblankStart and flip?
IF the whole sourcecode is what you posted, a main loop is also missing (this means the interpreter will just crash when the script reaches the end since even a System.exit is missing.
 

ElyosOfTheAbyss

Well-Known Member
Member
Joined
Aug 20, 2015
Messages
2,225
Trophies
1
XP
1,901
Country
Are you calling waitVblankStart and flip?
IF the whole sourcecode is what you posted, a main loop is also missing (this means the interpreter will just crash when the script reaches the end since even a System.exit is missing.
Yeah thats my whole source code, okay so I added waitVblankStart and the flip thing and the system.exit but just a black screen even when I press A


Code:
Menu = Screen.loadImage(System.currentDirectory().."Menu.bmp")

Screen.flip()
Screen.waitVblankStart()

Screen.drawImage(100,127,Menu,TOP_SCREEN)

if (Controls.check(Controls.read(),KEY_A)) then
  if Network.isWifiEnabled() then

      Screen.debugPrint(0,0,"Downloading: Please Wait",Color.new(255,255,255),BOTTOM_SCREEN)

        -- Download a file
        Network.downloadFile("LinkRemoved","/Downloaded.zip")

        -- Extract the file
        System.extractZIP("/Downloaded.zip",System.currentDirectory().."/")

       -- Delete the temp file
       System.deleteFile("/Downloaded.zip")

     dofile(System.currentDirectory().."news.lua")
     end
end
System.exit()

Is there anything im missing or anything that should be in there?
 

Rinnegatamante

Well-Known Member
OP
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Yeah thats my whole source code, okay so I added waitVblankStart and the flip thing and the system.exit but just a black screen even when I press A


Code:
Menu = Screen.loadImage(System.currentDirectory().."Menu.bmp")

Screen.flip()
Screen.waitVblankStart()

Screen.drawImage(100,127,Menu,TOP_SCREEN)

if (Controls.check(Controls.read(),KEY_A)) then
  if Network.isWifiEnabled() then

      Screen.debugPrint(0,0,"Downloading: Please Wait",Color.new(255,255,255),BOTTOM_SCREEN)

        -- Download a file
        Network.downloadFile("LinkRemoved","/Downloaded.zip")

        -- Extract the file
        System.extractZIP("/Downloaded.zip",System.currentDirectory().."/")

       -- Delete the temp file
       System.deleteFile("/Downloaded.zip")

     dofile(System.currentDirectory().."news.lua")
     end
end
System.exit()

Is there anything im missing or anything that should be in there?

Before any kind of scren drawing you must call a Screen.refresh. I highly suggest you to take a look at the CPU Rendering samples ( https://github.com/Rinnegatamante/lpp-3ds/tree/master/samples/CPU Rendering ).
 

Poketard

Well-Known Member
Member
Joined
Apr 3, 2013
Messages
180
Trophies
1
XP
1,490
Country
United States
When I try to use Socket.createServerSocket(port) with port as 51268 it errors saying invalid socket. Occurs no matter what port I have set up. I have Socket.init() set up, what am I doing wrong?
 

umbjolt

Wild jolteon
Member
Joined
Sep 15, 2016
Messages
558
Trophies
0
Age
27
Location
Magnolia, Fiore
XP
316
Country
Hi! I'm trying to make System.getTime, getBatteryLife and getDate refresh after changing but I'm unable to do it.
In the while I check if for example getTime has changed and if it change, it refresh the screen but I doesn't work. For example:

Code:
while true do
   pad = Controls.read()

   if Controls.check(pad,KEY_B) then
     System.exit()
   end

   local newHour, newMin, newSeg= System.getTime()
   if not newSeg == oldSeg then  
     setNewRefresh();
   else
     Screen.clear(TOP_SCREEN)
   end
end

and as you guest, it only clear the top screen.

Could you help me or explain why this happend? I'm used to use Java and C and this type of programing with whiles make me mad :wacko:
Thanks for all.
 

Rinnegatamante

Well-Known Member
OP
Member
Joined
Nov 24, 2014
Messages
3,162
Trophies
2
Age
29
Location
Bologna
Website
rinnegatamante.it
XP
4,857
Country
Italy
Hi! I'm trying to make System.getTime, getBatteryLife and getDate refresh after changing but I'm unable to do it.
In the while I check if for example getTime has changed and if it change, it refresh the screen but I doesn't work. For example:

Code:
while true do
   pad = Controls.read()

   if Controls.check(pad,KEY_B) then
     System.exit()
   end

   local newHour, newMin, newSeg= System.getTime()
   if not newSeg == oldSeg then 
     setNewRefresh();
   else
     Screen.clear(TOP_SCREEN)
   end
end

and as you guest, it only clear the top screen.

Could you help me or explain why this happend? I'm used to use Java and C and this type of programing with whiles make me mad :wacko:
Thanks for all.

With this portion of code i can't say you where you're wrong. What setNewREfresh does? (Also the ; is not used in lua for the sequence command).

P.s. Java and C both have whiles or they couldn't be called Touring complete languages like they are.
 
  • Like
Reactions: umbjolt

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    K3Nv2 @ K3Nv2: they be like which lite firefox exe pls