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

  • Thread starter Thread starter Rinnegatamante
  • Start date Start date
  • Views Views 187,228
  • Replies Replies 1,199
  • Likes Likes 35
Another day lost trying to search a fix for sound system with @ihaveamac and got this results:

- old libctru + old csnd (like original lpp-3ds r3): freeze when trying to start the song on NH 2.5, works fine on NH 2.1
- new libctru + new csnd with LINEAR_INTERP: corrupted sound (like wrong samplerate) on NH 2.5, corrupted sound on NH 2.1
- new libctru + old csnd: freeze when trying to start the song on NH 2.5, corrupted sound on NH 2.1
- new libctru + old csnd (using mappableAlloc) for CSND_Initialize: freeze when trying to start the song on NH 2.5, corrupted sound on NH 2.1
- new libctru + new csnd without LINEAR_INTERP: freeze when trying to start the song on NH 2.5, corrupted sound on NH 2.1


What does using or not using new libctru means not talking about sound on NH 2.5:

- new libctru have networking features fixxed, random errors (don't know how to patch) on several functions (like System.getBatteryLevel)
- old libctru have networking features broken


Just to let know if someone wants to try to understand where the problem is.
@smealum you asked me to search for assistence so, do you know what could be the problem? Even if i use latest commit of ctrulib, sound is completely corrupted when with old libctru and old csnd wrapper (like the one used in CHMM2) everything works fine at least on NH 2.1 and NH 1.1b.
Oh gosh. Sounded like you wasted a long time. Hopefully you don't get too crazy over working on this, you go yandere. XD (I'm sorry I had to go there because your profile picture)
 
Is there any way I can draw new stuff on the screen, over the top of what's already there, without having to clear the screen and draw it all over again? I'm trying to optimize my script because currently it's running at like 5 frames per second.

And do notes slow down lpp? Because I have a lot of them.
 
Last edited by HexZyle,
Is there any way I can draw new stuff on the screen, over the top of what's already there, without having to clear the screen and draw it all over again? I'm trying to optimize my script because currently it's running at like 5 frames per second.

And do notes slow down lpp? Because I have a lot of them.

It depends on your code, post it please.
 
The annoted out "redraw" variable was part of me trying to disable redraws when they weren't needed (a value of 2 meant that the whole screen had been cleared, so redraw everything, a value of 1 meant that new stuff had been drawn but it was over the top of old stuff, and a value of 0 meant that nothing new had been updated this frame)

Yes, I know that the block at line 184 is a fucking doozy and it's the one that's slowing my program down while it's drawing new text. I want the text to stick around though, and not have to redraw it every frame, even if I'm refreshing stuff on the top screen. So far I've been unsuccessful though, any attempt I've had either makes my stuff clear instantly, or results in an epileptic fit-inducing refreshing sequence as the whole screen flickers black every frame.

Code:
Graphics.init() -- Init GPU
Sound.init() -- init Sound

white = Color.new(255,255,255)
black = Color.new(0,0,0)
red = Color.new(255,0,0)
blue = Color.new(0,0,255)
green = Color.new(0,255,0)

c00 = Color.new(226,90,90) --red
c15 = Color.new(30,38,15)
c30 = Color.new(61,76,30)
c45 = Color.new(92,114,45)
c60 = Color.new(123,153,61)
c75 = Color.new(154,191,76)
c90 = Color.new(183,229,91)

oldpad = Controls.read()

--LOAD RESOURCES /////////////////////////////////////////
img_cli_background = Screen.loadImage(System.currentDirectory().."/images/cli_background.png")
img_cli_header = Screen.loadImage(System.currentDirectory().."/images/cli_header.png")
img_menu_background = Screen.loadImage(System.currentDirectory().."/images/menu_background.png")
img_menu_main = Screen.loadImage(System.currentDirectory().."/images/menu_main.png")
img_arc_logingui = Screen.loadImage(System.currentDirectory().."/images/arc_logingui.png")
img_arc_uploader = Screen.loadImage(System.currentDirectory().."/images/arc_uploader.png")
img_arc_uploader_pip = Screen.loadImage(System.currentDirectory().."/images/arc_uploader_pip.png")
img_blank = Screen.createImage(20,20,white)

wav_boot = Sound.openWav(System.currentDirectory().."/sounds/boot.wav")

fnt_small = Font.load(System.currentDirectory().."/fonts/3by5.ttf")
Font.setPixelSizes(fnt_small,5)

dofile(System.currentDirectory().."/gamedata/ds_queue_init.lua")

q_commands = {}
--q_commands.value = {}
q_commands.fontcol = {}

ds_queue_create(q_commands)
--ds_queue_create(q_commands.value)
ds_queue_create(q_commands.fontcol)

dofile(System.currentDirectory().."/gamedata/text_init.lua")
ds_queue_stack(q_commands,txt.startup)
ds_queue_stack(q_commands.fontcol,txt.startup.fontcol)

dofile(System.currentDirectory().."/gamedata/fps_init.lua")

redraw = 2
--redraw = {}
--redraw[TOP_SCREEN] = 2
--redraw[BOTTOM_SCREEN] = 2

dofile(System.currentDirectory().."/gamedata/commands_init.lua")

--////////////////////////////////////////////////////////
--Programs and Gui
--////////////////////////////////////////////////////////

topscreen_enabled = false

logingui_arc = false
mainmenu_arc = false
filebrowser_arc = false
bbs_arc = false
rvemail_arc = false
keyboard_arc = false
uploader_arc = false

biosbusy = false

local i = 1
cli_text = {}
repeat
    cli_text[i] = ''
    --cli_text[i].value = {} --the value table is used for customizable data per line... not needed yet
    cli_text[i+50] = c30 --plus 50 is the magic number for "font"
    i = i+1
until i==35
cli_text.index = 0

--BOOT SECT--
boot = false

debugstr = ''

while true do
    pad = Controls.read()
    tx,ty = Controls.readTouch()
  
    if boot == false then --PRE BOOT STAGE/////////////////////////////////////////
        Screen.waitVblankStart()
        Screen.refresh()
        Screen.clear(TOP_SCREEN)
        Screen.clear(BOTTOM_SCREEN)
  
        Screen.debugPrint(6,6,"Press X to launch RomanVault", white, TOP_SCREEN)
        if (Controls.check(pad,KEY_X)) then
            boot = true
            Screen.clear(TOP_SCREEN)
            Screen.clear(BOTTOM_SCREEN)
            --Sound.play(wav_boot,NO_LOOP,0x09)
        end
      
        if (Controls.check(pad,KEY_SELECT)) and not (Controls.check(oldpad,KEY_SELECT)) then
            local user = System.getUsername()
            --System.addNotification("Welcome",user..", RomanVault awaits you.")
        end
    else --/////////////////////////////////////////////////////////////////////////
        --if (Controls.check(pad,KEY_B)) and not (Controls.check(oldpad,KEY_B)) then
        --    Screen.saveBitmap(bitmap2,"/bitmap.bmp")
        --    System.takeScreenshot("/screenshot.bmp",false)
        --end
      
        --SHIFTING QUEUED COMMANDS TO THE COMMAND LINE INTERFACE
      
        if q_commands.size > 0 and biosbusy == false then
            if cli_text.index == 24 then --we shift all the lines down, and then add the new line to 35
                --redraw=2
                local i = 1
                repeat
                    cli_text[i] = cli_text[i+1]
                    cli_text[i+50] = cli_text[i+1+50]
                    --cli_text[i].value = cli_text[i+1].value
                    i = i+1
                until i==24
                local str = ds_queue_dequeue(q_commands)
                str = read_command(str)
                cli_text[i] = str
                --cli_text[i] = ds_queue_dequeue(q_commands)
                cli_text[i+50] = ds_queue_dequeue(q_commands.fontcol)
                --cli_text[i].value = ds_queue_dequeue(q_commands.value)
            else --we add the value to the index and add one to index
                --redraw=1
                cli_text.index = cli_text.index + 1
                local str = ds_queue_dequeue(q_commands)
                str = read_command(str)
                cli_text[cli_text.index] = str
                --cli_text[cli_text.index] = ds_queue_dequeue(q_commands)
                cli_text[cli_text.index +50] = ds_queue_dequeue(q_commands.fontcol)
            end
        end
      
        if biosbusy == true then
            --bios queued commands here
            process_command()
        end
      
        --START OF DRAW FUNCTIONS/////////////////////////////
        Screen.waitVblankStart()
        Screen.refresh()
        --Screen.clear(TOP_SCREEN)
        --Screen.clear(BOTTOM_SCREEN)
        --if redraw == 2 then
            Screen.clear(TOP_SCREEN)
            Screen.clear(BOTTOM_SCREEN)
        --end
        --if redraw[TOP_SCREEN] ==2 then Screen.clear(TOP_SCREEN) end
        --if redraw[BOTTOM_SCREEN]==2 then Screen.clear(BOTTOM_SCREEN) end
      
        Screen.debugPrint(6,20,"q_commands.size = "..q_commands.size, white, TOP_SCREEN)
        Screen.debugPrint(6,34,"debugstr = "..debugstr, white, TOP_SCREEN)
      
        --TOP SCREEN//////////////////////////////////////////
        if topscreen_enabled then
            --if redraw==2 then
                Screen.drawImage(0,0,img_menu_background,TOP_SCREEN)          
                Screen.drawImage(0,0,img_menu_main,TOP_SCREEN)
            --end
        end
      
        fps_draw()
      
        --BOTTOM SCREEN///////////////////////////////////////
        --if redraw==2 then
            Screen.drawImage(0,0,img_cli_background,BOTTOM_SCREEN)
            Screen.drawImage(0,0,img_cli_header,BOTTOM_SCREEN)
        --end
      
        --if redraw>1 then
            local i=1
            while i < cli_text.index + 1 do
                if cli_text[i] ~= nil then --as long as the line actually has text in it? Otherwise it errors
                    Font.print(fnt_small, 1, 6*i +15, cli_text[i],cli_text[i+50],BOTTOM_SCREEN)
                end
                i=i+1
            end
      
            if logingui_arc then
                Screen.drawImage(0,0,img_arc_logingui,BOTTOM_SCREEN)
            end
          
            if uploader_arc then
                Screen.drawImage(87,105,img_arc_uploader,BOTTOM_SCREEN)
                local i = 0
                while i < uploader_arc_progress do
                    Screen.drawImage(97+(i*3),117,img_arc_uploader_pip,BOTTOM_SCREEN)
                    i = i+1
                end
            end
        --end
        --END OF DRAW FUNCTION/////////////////////////////////      
        --redraw[TOP_SCREEN] = 0
        --redraw[BOTTOM_SCREEN] = 0
        --redraw=0
        --/////
      
    end
  
    --THESE FUNCTIONS ALWAYS RUN///////////////////////////////
    if (Controls.check(pad,KEY_START)) then --shutdown sequence
        Graphics.term()
        Sound.close(wav_boot)
        Sound.term()
        System.exit()
    end  
    Screen.flip()
    oldpad = pad
end
 
The annoted out "redraw" variable was part of me trying to disable redraws when they weren't needed (a value of 2 meant that the whole screen had been cleared, so redraw everything, a value of 1 meant that new stuff had been drawn but it was over the top of old stuff, and a value of 0 meant that nothing new had been updated this frame)

Yes, I know that the block at line 184 is a fucking doozy and it's the one that's slowing my program down while it's drawing new text. I want the text to stick around though, and not have to redraw it every frame, even if I'm refreshing stuff on the top screen. So far I've been unsuccessful though, any attempt I've had either makes my stuff clear instantly, or results in an epileptic fit-inducing refreshing sequence as the whole screen flickers black every frame.

Code:
Graphics.init() -- Init GPU
Sound.init() -- init Sound

white = Color.new(255,255,255)
black = Color.new(0,0,0)
red = Color.new(255,0,0)
blue = Color.new(0,0,255)
green = Color.new(0,255,0)

c00 = Color.new(226,90,90) --red
c15 = Color.new(30,38,15)
c30 = Color.new(61,76,30)
c45 = Color.new(92,114,45)
c60 = Color.new(123,153,61)
c75 = Color.new(154,191,76)
c90 = Color.new(183,229,91)

oldpad = Controls.read()

--LOAD RESOURCES /////////////////////////////////////////
img_cli_background = Screen.loadImage(System.currentDirectory().."/images/cli_background.png")
img_cli_header = Screen.loadImage(System.currentDirectory().."/images/cli_header.png")
img_menu_background = Screen.loadImage(System.currentDirectory().."/images/menu_background.png")
img_menu_main = Screen.loadImage(System.currentDirectory().."/images/menu_main.png")
img_arc_logingui = Screen.loadImage(System.currentDirectory().."/images/arc_logingui.png")
img_arc_uploader = Screen.loadImage(System.currentDirectory().."/images/arc_uploader.png")
img_arc_uploader_pip = Screen.loadImage(System.currentDirectory().."/images/arc_uploader_pip.png")
img_blank = Screen.createImage(20,20,white)

wav_boot = Sound.openWav(System.currentDirectory().."/sounds/boot.wav")

fnt_small = Font.load(System.currentDirectory().."/fonts/3by5.ttf")
Font.setPixelSizes(fnt_small,5)

dofile(System.currentDirectory().."/gamedata/ds_queue_init.lua")

q_commands = {}
--q_commands.value = {}
q_commands.fontcol = {}

ds_queue_create(q_commands)
--ds_queue_create(q_commands.value)
ds_queue_create(q_commands.fontcol)

dofile(System.currentDirectory().."/gamedata/text_init.lua")
ds_queue_stack(q_commands,txt.startup)
ds_queue_stack(q_commands.fontcol,txt.startup.fontcol)

dofile(System.currentDirectory().."/gamedata/fps_init.lua")

redraw = 2
--redraw = {}
--redraw[TOP_SCREEN] = 2
--redraw[BOTTOM_SCREEN] = 2

dofile(System.currentDirectory().."/gamedata/commands_init.lua")

--////////////////////////////////////////////////////////
--Programs and Gui
--////////////////////////////////////////////////////////

topscreen_enabled = false

logingui_arc = false
mainmenu_arc = false
filebrowser_arc = false
bbs_arc = false
rvemail_arc = false
keyboard_arc = false
uploader_arc = false

biosbusy = false

local i = 1
cli_text = {}
repeat
    cli_text[i] = ''
    --cli_text[i].value = {} --the value table is used for customizable data per line... not needed yet
    cli_text[i+50] = c30 --plus 50 is the magic number for "font"
    i = i+1
until i==35
cli_text.index = 0

--BOOT SECT--
boot = false

debugstr = ''

while true do
    pad = Controls.read()
    tx,ty = Controls.readTouch()
 
    if boot == false then --PRE BOOT STAGE/////////////////////////////////////////
        Screen.waitVblankStart()
        Screen.refresh()
        Screen.clear(TOP_SCREEN)
        Screen.clear(BOTTOM_SCREEN)
 
        Screen.debugPrint(6,6,"Press X to launch RomanVault", white, TOP_SCREEN)
        if (Controls.check(pad,KEY_X)) then
            boot = true
            Screen.clear(TOP_SCREEN)
            Screen.clear(BOTTOM_SCREEN)
            --Sound.play(wav_boot,NO_LOOP,0x09)
        end
     
        if (Controls.check(pad,KEY_SELECT)) and not (Controls.check(oldpad,KEY_SELECT)) then
            local user = System.getUsername()
            --System.addNotification("Welcome",user..", RomanVault awaits you.")
        end
    else --/////////////////////////////////////////////////////////////////////////
        --if (Controls.check(pad,KEY_B)) and not (Controls.check(oldpad,KEY_B)) then
        --    Screen.saveBitmap(bitmap2,"/bitmap.bmp")
        --    System.takeScreenshot("/screenshot.bmp",false)
        --end
     
        --SHIFTING QUEUED COMMANDS TO THE COMMAND LINE INTERFACE
     
        if q_commands.size > 0 and biosbusy == false then
            if cli_text.index == 24 then --we shift all the lines down, and then add the new line to 35
                --redraw=2
                local i = 1
                repeat
                    cli_text[i] = cli_text[i+1]
                    cli_text[i+50] = cli_text[i+1+50]
                    --cli_text[i].value = cli_text[i+1].value
                    i = i+1
                until i==24
                local str = ds_queue_dequeue(q_commands)
                str = read_command(str)
                cli_text[i] = str
                --cli_text[i] = ds_queue_dequeue(q_commands)
                cli_text[i+50] = ds_queue_dequeue(q_commands.fontcol)
                --cli_text[i].value = ds_queue_dequeue(q_commands.value)
            else --we add the value to the index and add one to index
                --redraw=1
                cli_text.index = cli_text.index + 1
                local str = ds_queue_dequeue(q_commands)
                str = read_command(str)
                cli_text[cli_text.index] = str
                --cli_text[cli_text.index] = ds_queue_dequeue(q_commands)
                cli_text[cli_text.index +50] = ds_queue_dequeue(q_commands.fontcol)
            end
        end
     
        if biosbusy == true then
            --bios queued commands here
            process_command()
        end
     
        --START OF DRAW FUNCTIONS/////////////////////////////
        Screen.waitVblankStart()
        Screen.refresh()
        --Screen.clear(TOP_SCREEN)
        --Screen.clear(BOTTOM_SCREEN)
        --if redraw == 2 then
            Screen.clear(TOP_SCREEN)
            Screen.clear(BOTTOM_SCREEN)
        --end
        --if redraw[TOP_SCREEN] ==2 then Screen.clear(TOP_SCREEN) end
        --if redraw[BOTTOM_SCREEN]==2 then Screen.clear(BOTTOM_SCREEN) end
     
        Screen.debugPrint(6,20,"q_commands.size = "..q_commands.size, white, TOP_SCREEN)
        Screen.debugPrint(6,34,"debugstr = "..debugstr, white, TOP_SCREEN)
     
        --TOP SCREEN//////////////////////////////////////////
        if topscreen_enabled then
            --if redraw==2 then
                Screen.drawImage(0,0,img_menu_background,TOP_SCREEN)         
                Screen.drawImage(0,0,img_menu_main,TOP_SCREEN)
            --end
        end
     
        fps_draw()
     
        --BOTTOM SCREEN///////////////////////////////////////
        --if redraw==2 then
            Screen.drawImage(0,0,img_cli_background,BOTTOM_SCREEN)
            Screen.drawImage(0,0,img_cli_header,BOTTOM_SCREEN)
        --end
     
        --if redraw>1 then
            local i=1
            while i < cli_text.index + 1 do
                if cli_text[i] ~= nil then --as long as the line actually has text in it? Otherwise it errors
                    Font.print(fnt_small, 1, 6*i +15, cli_text[i],cli_text[i+50],BOTTOM_SCREEN)
                end
                i=i+1
            end
     
            if logingui_arc then
                Screen.drawImage(0,0,img_arc_logingui,BOTTOM_SCREEN)
            end
         
            if uploader_arc then
                Screen.drawImage(87,105,img_arc_uploader,BOTTOM_SCREEN)
                local i = 0
                while i < uploader_arc_progress do
                    Screen.drawImage(97+(i*3),117,img_arc_uploader_pip,BOTTOM_SCREEN)
                    i = i+1
                end
            end
        --end
        --END OF DRAW FUNCTION/////////////////////////////////     
        --redraw[TOP_SCREEN] = 0
        --redraw[BOTTOM_SCREEN] = 0
        --redraw=0
        --/////
     
    end
 
    --THESE FUNCTIONS ALWAYS RUN///////////////////////////////
    if (Controls.check(pad,KEY_START)) then --shutdown sequence
        Graphics.term()
        Sound.close(wav_boot)
        Sound.term()
        System.exit()
    end 
    Screen.flip()
    oldpad = pad
end

If you have to work with such a big number of images, just use GPU (Graphics module) instead of CPU (Screen module). It will massively boost your framerate.
 
If you have to work with such a big number of images, just use GPU (Graphics module) instead of CPU (Screen module). It will massively boost your framerate.

This is text, not images. 24 lines of text, and the 3DS is chugging when it pulls each one out of an array and draws all 24 lines individually every step. I thought there might have been a way to not update the screen when nothing new is happening in order to increase response time.
 
Everytime you update the screen, you re-blit images on the screen. CPU rendering is very bad for images blit (especially for PNG images which are saved in memory as 32 bpp images instead of 24 bpp (JPG / BMP) so they take also extra time to proper do alpha blending).
 
So is there any way to draw a large amount of (dynamic) text in GPU mode? Would I create text, and then convert it to an image each time?
 
So is there any way to draw a large amount of (dynamic) text in GPU mode? Would I create text, and then convert it to an image each time?

Right now, lpp-3ds doesn't support GPU text rendering but re-blending images with GPU is much more faster then CPU ones. You shouldn't have any framedrop.
 
So is there any way to draw a large amount of (dynamic) text in GPU mode? Would I create text, and then convert it to an image each time?
If I were you I would try drawing 24 static strings and see if that performs at the same speed. Even with CPU rending I don't think it should be quite this slow, but it is possible. But @Rinnegatamante is suggesting you replace the Screen.drawImage calls with GPU rendering in order to speed those up significantly, which should give your Font calls more time to render.
 
Right now, lpp-3ds doesn't support GPU text rendering but re-blending images with GPU is much more faster then CPU ones. You shouldn't have any framedrop.
What if I created images of each letter, and then built a script that "wrote" my text using the assembled letter images? Would that be horrendously laggy, or would it work fine?

If I were you I would try drawing 24 static strings and see if that performs at the same speed. Even with CPU rending I don't think it should be quite this slow, but it is possible. But @Rinnegatamante is suggesting you replace the Screen.drawImage calls with GPU rendering in order to speed those up significantly, which should give your Font calls more time to render.

OH I see, so the GPU could handle the images while the CPU handled the text... sort of like multithreading?
 
What if I created images of each letter, and then built a script that "wrote" my text using the assembled letter images? Would that be horrendously laggy, or would it work fine?

It would work fine (it's what Font module does but with CPU rendering) but you should write a proper rendering function which take count of glyph size and all other things about your font).
 
It would work fine (it's what Font module does but with CPU rendering) but you should write a proper rendering function which take count of glyph size and all other things about your font).

My font is monospaced (in fact each character is 3x5, except for Ms and Ws which are designed to take up 2 character spaces) so I don't need to care about glyph size
scene02.png
 
Bah! How does one create a string solely consisting of a backslash without some ridiculous workaround? Notepad++ is acting weird about it, and I'm not sure if a lua interpreter will too.
 
Alright, I made my own gpu drawtext script, and after I switched my whole program over to gpu instead of cpu, the framerate improvement is like night and day.
The loading time though for the program has taken a pretty big hit as I have to load the font in (although I do have every letter as a separate image, I think I might be able to get a huge speed boost if I loaded in the font as a single image, and used the partial draw functions)

Thanks for all the help!
 
Last edited by HexZyle,
Alright, I made my own gpu drawtext script, and after I switched my whole program over to gpu instead of cpu, the framerate improvement is like night and day.

Thanks for all the help!
How does it work out of curiosity, I'm interested ;)
 
How does it work out of curiosity, I'm interested ;)

I load all the characters into individual images (although it takes a while, I think loading in a single sheet and then using Graphics.drawPartialImage() would be way better for load times)

Note that my characters are monospaced,so I don't need to worry about how far along to draw each letter (except for M and W which are double width, but they're currently being converted in the text parser from "M" to "M " and "W" to "W ". It's a little clumsy having it actually saved in the strings like that so I plan to change it soon so that it's handled by this function instead)

The *4 at the Graphics.drawImage line is because my font's characters are 3 pixels wide, with a spacing of 1 pixel between them.

Code:
        gpuglyph = {}
        gpuglyph['A'] = Graphics.loadImage(System.currentDirectory().."/fonts/A.png")
        gpuglyph['B'] = Graphics.loadImage(System.currentDirectory().."/fonts/B.png")
        gpuglyph['C'] = Graphics.loadImage(System.currentDirectory().."/fonts/C.png")
        gpuglyph['D'] = Graphics.loadImage(System.currentDirectory().."/fonts/D.png")
        gpuglyph['E'] = Graphics.loadImage(System.currentDirectory().."/fonts/E.png")
        gpuglyph['F'] = Graphics.loadImage(System.currentDirectory().."/fonts/F.png")
        gpuglyph['G'] = Graphics.loadImage(System.currentDirectory().."/fonts/G.png")
        gpuglyph['H'] = Graphics.loadImage(System.currentDirectory().."/fonts/H.png")
        gpuglyph['I'] = Graphics.loadImage(System.currentDirectory().."/fonts/I.png")
        gpuglyph['J'] = Graphics.loadImage(System.currentDirectory().."/fonts/J.png")
        gpuglyph['K'] = Graphics.loadImage(System.currentDirectory().."/fonts/K.png")
        gpuglyph['L'] = Graphics.loadImage(System.currentDirectory().."/fonts/L.png")
        gpuglyph['M'] = Graphics.loadImage(System.currentDirectory().."/fonts/M.png")
        gpuglyph['N'] = Graphics.loadImage(System.currentDirectory().."/fonts/N.png")
    --you get the point

        function gpu_drawtext(x, y, text, font_color) --there was an i_pos planned to take account of that M and W use up two spaces, but I can put that in later
            local i_str=0 --(byte) the current position in the string
            local i_chr='' --(string) the character at position i_str of the string
            local i_img=nil --(file id) the image file representing the character
            local str_length = string.len(text)
            while i_str < str_length do
                i_str = i_str + 1 --go to next character in the string
                i_chr = string.sub(text, i_str, i_str) --obtain character
                i_img = gpuglyph[i_chr] --lookup image file for said character
                Graphics.drawImage(x+((i_str-1)*4), y, i_img, font_color)
            end
        end
 
Last edited by HexZyle,
  • Like
Reactions: Rinnegatamante
I load all the characters into individual images (although it takes a while, I think loading in a single sheet and then using Graphics.drawPartialImage() would be way better for load times)

Note that my characters are monospaced,so I don't need to worry about how far along to draw each letter (except for M and W which are double width, but they're currently being converted in the text parser from "M" to "M " and "W" to "W ". It's a little clumsy having it actually saved in the strings like that so I plan to change it soon so that it's handled by this function instead)

The *4 at the Graphics.drawImage line is because my font's characters are 3 pixels wide, with a spacing of 1 pixel between them.

Code:
        gpuglyph = {}
        gpuglyph['A'] = Graphics.loadImage(System.currentDirectory().."/fonts/A.png")
        gpuglyph['B'] = Graphics.loadImage(System.currentDirectory().."/fonts/B.png")
        gpuglyph['C'] = Graphics.loadImage(System.currentDirectory().."/fonts/C.png")
        gpuglyph['D'] = Graphics.loadImage(System.currentDirectory().."/fonts/D.png")
        gpuglyph['E'] = Graphics.loadImage(System.currentDirectory().."/fonts/E.png")
        gpuglyph['F'] = Graphics.loadImage(System.currentDirectory().."/fonts/F.png")
        gpuglyph['G'] = Graphics.loadImage(System.currentDirectory().."/fonts/G.png")
        gpuglyph['H'] = Graphics.loadImage(System.currentDirectory().."/fonts/H.png")
        gpuglyph['I'] = Graphics.loadImage(System.currentDirectory().."/fonts/I.png")
        gpuglyph['J'] = Graphics.loadImage(System.currentDirectory().."/fonts/J.png")
        gpuglyph['K'] = Graphics.loadImage(System.currentDirectory().."/fonts/K.png")
        gpuglyph['L'] = Graphics.loadImage(System.currentDirectory().."/fonts/L.png")
        gpuglyph['M'] = Graphics.loadImage(System.currentDirectory().."/fonts/M.png")
        gpuglyph['N'] = Graphics.loadImage(System.currentDirectory().."/fonts/N.png")
    --you get the point

        function gpu_drawtext(x, y, text, font_color) --there was an i_pos planned to take account of that M and W use up two spaces, but I can put that in later
            local i_str=0 --(byte) the current position in the string
            local i_chr='' --(string) the character at position i_str of the string
            local i_img=nil --(file id) the image file representing the character
            local str_length = string.len(text)
            while i_str < str_length do
                i_str = i_str + 1 --go to next character in the string
                i_chr = string.sub(text, i_str, i_str) --obtain character
                i_img = gpuglyph[i_chr] --lookup image file for said character
                Graphics.drawImage(x+((i_str-1)*4), y, i_img, font_color)
            end
        end

Very cool, thanks for the explanation.
 

Site & Scene News

Popular threads in this forum