Homebrew 3DS Junk draw

  • Thread starter Thread starter haloopdy
  • Start date Start date
  • Views Views 9,735
  • Replies Replies 46
  • Likes Likes 15
im posting more of my cookings here, junkdraw genuinely gets me out of art block and im grateful for its existence
gosh, you're inspiring me to clean up the app even more! if i can get myself moving, i think i will work on some neat additional features. i've added a bunch of issues to the repo to give myself a todo list

Edit: might as well share the last thing i drew too, since i've been using junkdraw again:

HAL2__36_1785728485_cropped.png
 
Last edited by haloopdy,
YAYAYAYA ITS SOO ADORABLE!!!!! I luv the blep face... May i request a textured brush...... i looove textured brushes and i think theyd add charm to teh drawings easily
 
  • Wow
Reactions: haloopdy
YAYAYAYA ITS SOO ADORABLE!!!!! I luv the blep face... May i request a textured brush...... i looove textured brushes and i think theyd add charm to teh drawings easily
aww thank you so much!!

i would love to add a textured brush (i like using them too), but it has a couple problems.

one is that i wanted to keep the drawing format very simple so it's easy to re-implement. i like the idea of longevity and/or inter-connected drawing (if i ever do that), and it gets harder to recreate a drawing from the save data if i make complicated brushes. but maybe that's not important anymore... i don't know how i feel about it yet lol. like, i like imagining one day when all the 3ds's are broken and i want to look at old art, that i'd quickly throw together a web viewer for save files.

two is just that i think that would have to wait until i switch to software rendering, and i'm not sure how slow that would be. i'm currently using hardware rendering so it's ridiculously fast to draw and render, keeping the app feeling smooth. the other drawing app recently made (Magic Draw) is software rendered and it's very impressive and does a ton of stuff mine doesn't do, but it's slow and i am autistic and need the marks to show up smoothly otherwise i go crazy lol.


idk though, if i can figure out how to do it in hardware in a way that's easy to reimplement in the future, i will try!
 
Ooo I see! Thank you for replying :0 Yes magicdraw is so slow, its cool and all but its so laggy😔 so i prefer junkdraw despite its limitations djjshdjjf
 
Listing out the features already in 0.6 so I don't forget, because IDK when I'll have time to test this. It's required such a huge redo of so much code:
  • Removed "mode switching" (to animation mode, etc) in favor of more control over the canvas
  • Added canvas settings saved into the save file:
    • Choose from one of three resolutions: 1000x1000, 500x500, and 320x240 (1:1 screen size)
    • Choose amount layers; depends on resolution. You get access to more layers at lower resolutions
    • Choose amount of onion skin layers. Onion skins are now just fancy layers, so again it depends on your resolution
    • Choose canvas background color. I know this took forever but you can now do this, and it is saved into the drawing. A drawing can only have one background color, I don't plan on making per-page bg colors (sorry)
  • Fixed off-screen drawing messing up onion skins
    • NOTE: all off-screen drawing is preserved if you change resolutions, don't worry
  • Fixed exports with white paint on white backgrounds showing up as a different color
  • Small amount of caching of unused layers to help with animation smoothness. This may cause issues, not sure yet
  • Auto-hide scrollbars if they're not needed (helps clean up the UI on 320x240 drawing)
I want to personally test this for a while before I do even a pre-release, because the changes are so drastic. This codebase is a mess and I'm slowly pulling stuff out into slightly nicer modules but honestly my ability to reason about spaghetti code has decreased over the years and anything that isn't a newer module is hard for me to follow.
 
  • Like
Reactions: Axonic3D
i am completely rewriting the app; i'm very far into it. i started this app many years ago and i was not a very good c programmer at the time, having only worked with c# (which i hate). for the past several years, the ONLY thing i have been writing in is c for personal projects, so i understand the nuances and design strategies for memory management/apis/etc a lot better (or at least, i hope i do lol). as such, 0.6 may be a complete break from all the previous versions. not that save files will be incompatible (will try very hard to make them the same), however the feel and direction of the app may change a bit.

i still plan on keeping the console upper window, as it saves a bit on video memory and imo gives it a bit of charm. but the way it looks and works may be entirely different. the pagination, the palette, rgb sliders, etc should all remain the same, and it's still going to have no anti-aliasing on purpose. but, if things go well, i'm hoping it will have a lot more features (in time) and a lot more flexibility to add features. i've been really digging into the 3ds library and i feel like i've learned a ton about how it works and all the things i did wrong, and i think i have a system in place where you can still have 60fps drawing but have all the features that have been requested in the past: flood fill, color picker, custom brushes, etc. i am at least certain that a color picker and flood fill will make it in.

i'm very excited! but i also know that a rewrite comes with pain points, so i do plan on supporting 0.5.2 with bugfixes for the foreseeable future for anybody who just can't let the old one go. but i'm autistic and tbh it will probably feel the same as it did in the past, so hopefully anyone still interested in junkdraw will enjoy 0.6 more than the old ones.

if you are interested in following the development and code changes (for some reason?) the branch i'm working on is https://github.com/randomouscrap98/3ds_junkdraw/tree/softrend.

so in the past, i wrote code around "concepts", like "this is the drawing code" and "this is the file system code". i would make structs or data types that would string together fields i THOUGHT were related and then write loose functions all over the place to process data in those fields. this was bad: it would always lead to tons of spaghettii code because the fields that were related by some human concept were NOT necessarily related in code or the way the data is ACTUALLY used, so every struct just kinda had to go everywhere, save for the very lowest functions. i think i did this because i hated object oriented programming (since i hated working with c#) and tried to avoid doing it, but i think that hatred was unfounded. i think i was just using objects wrong, and c# is just a bad language imo lol.

as i've been writing more c projects of larger and larger scope for the past several years (including a game engine from scratch, just for fun and of no real use), i've slowly been adopting a more object-oriented approach, but with a data-driven design rather than a conceptual one. i used to program for "humans" so to speak: i would design my classes in such a way where stuff that "conceptually" went together did. i never understood why this rarely worked out, and why it always become so difficult to work with, but it's because the way data flows in a program is not often tied to our real-life concepts. sure, putting all the "drawing" related data together sounds good, but some of that drawing stuff is only related to the UI, and some of it is only related to data conversion INTO the drawing primitives, and you can see how everything starts to get tangled together perhaps. "drawing" is now dependent on the data format, because the raw data is converted into drawing primitives, and now the drawing primitives might be used for SOME ui tasks.

now, instead of programming for a nebulous "future self" and how i might want things organized, i program for the COMPUTER and how the ACTUAL DATA flows. no system cares about the format of the encoded save data, just that they can get what they want out of it. the data encoding system doesn't care about the format the drawing primitives expect, it only cares about the way it is structured within itself. so, i designed a data encoding and decoding "class" (in c it's just a struct that holds related data to encoding and decoding, plus functions which operate on this struct) whose "api" so to speak is just that you can dump data packages into it and take them out. the data packages are NOT the drawing primitives, they're just the structs which represent the underlying encoded data. then, i wrote a "layer" class which handles drawing into a buffer. maybe this seems obvious to most, but i guess i had lost the plot on programming lol. the layer class accepts its own data format: drawing primitives it knows how to render. these are DIFFERENT than the ones i store into the data encoder. then there's a connecting class "lineconverter" which can translate stuff from the data encoder format to the layer format. so i have core classes which are self contained and don't depend on other modules, and connecting tissue to help link them together. it forms a well-defined tree which is far easier to reason about and work on. and yes, i get that this is like... what most people learn in college in like programming 202 or whatever, but tbh it took me many years to really get a feel for "what" to put into a class. you can really break up your code any way you want, and some ways to break up code end up as a mess. imagine sorting pots and pans: you could sort by shape, or by type, or by how they are used. maybe some ways take up less space in the cabinet but are harder to take stuff out or put stuff in, maybe other ways allow quick access but take up a ton of space and you can't put as many in the cabinet. other ways may make sense to you because you're currently cooking a lot of the same stuff and keep the oft-used pots and pans easy to reach, but in the future this may break down because now you're cooking different things. i think it takes some people (like myself) many years before you find a way that works "in general" and when/why you might want to break the rules.

anyway, point is that now that i have a wrapped up "layer" class, i have pulled all the weird rendering code out of the rest of the codebase and it's all in one place, so now i was able to make a layer be either software rendered or hardware rendered. i had to learn a ton about how vram textures work (which was EXTREMELY difficult to find!!!) but now that a layer can either be software or hardware rendered, and you can convert between the two on the fly, it should be easy to implement stuff like flood fill, as i can just temporarily convert the layer you're filling to software, query all the pixels as needed, output the appropriate draw commands to fill it, then convert it back to hardware for fast rendering. but if i get my way, i might be able to make all drawing be software rendered, which lets me do basically anything, and i just convert the layers into hardware as needed.

also with this new codebase, it's so much easier to write tests, so i now have a test app. it's only light testing, but it should prevent major bugs from popping up unexpectedly, or at the VERY least prevent bugs from "reappearing" once they are fixed. once i have a test for some edge case, i will always know if some change i make causes it to appear. i usually like writing tests for code and do it often, but i felt i was unable to foro this codebase for the longest time. it also helps me with code design, as keeping code "testable" also keeps it modular and easier to reason about. if something is difficult to test, it's also difficult to reason about.

anyway, if you read all that, thank you! just been working on this so much for the past several days and wanted to get it off my chest.
 

Site & Scene News

Popular threads in this forum