Ep. 123: Modifying Image Brightness - Game Programming

The Cherno · Intermediate ·10y ago

Key Takeaways

The video demonstrates modifying image brightness in game programming using Java and various tools such as Puffet image and UIL, with concepts including image processing, color channels, and byte array manipulation.

Full Transcript

hey what's up guys My Name Is AO and welcome to episode 123 of game programming so minutes earlier I recorded episode22 uh as you can literally quite see minutes have passed um and as soon as I finished recording that and I set up some editing and whatnot I realized that hang on the reason we were probably getting a Class cast exception with everything else was because the format wasn't actually an integer okay so this format you can see we set up with int which is why obviously casting this to a in probably Mak sense however the image that we loaded must not have been that format so just uh to ease my curiosity I'm going to go ahead and print the type of the image and see that it's type six whatever the hell that means so let's go into puffet image and see what the types are um so where are these defined so six is actually so it's a 4 byte abgr okay so that is why um it didn't work out so it looks like it's what does it say B AR lived in a single bite array okay so it's just a bite array abgr which means that it's going to be a bite array that's four times as large as the amount of pixels and uh it's just going to be the first buy is going to be a so index zero will be a then index one will be R and then or BGR it looks like so B then G then R okay that's all inter leave just means that it's kind of uh hint leave it's hard to uh to say actually I'm pretty sure yeah so excuse me so it just means that um if we want to access a particular int it'll be um a particular channel of color uh first of all we don't have to split them up using um uh anding essentially or masking we just we can just grab it uh using um the uh I guess we can just grab it using um just the you know B array indices and that's it so one thing I want to focus on today um the next big thing we'll be doing is actually creating a mini map and I want to save that for next time because there's a few things I want to do here and I don't want to uh I I don't want to shove everything into one episode like I did last time so um we've got some buttons there are a few things that are wrong first of all you can see that we shoot even if we click on these buttons that's a bit annoying I want to fix that but then the other thing I want to fix is actually uh this right I don't want to have this here but I do want a nice easy way to brighten something so I'm going to introduce uh something in UIL called image utils okay and these things are going to be uh stuff like I want to increase the brightness of an image of mine okay and it will return a new image so public this will be a static class so we go ahead and we'll actually create a private Constructor just so no one is tempted to make instances of this class ever and then we'll go ahead and excuse me and we'll say something like public static buffet image um uh what's a good name for this um change brightness why not uh so we'll take in a buffet image original and then [Music] um so this will actually uh create creates a new image this will actually to create a new image and then we'll see say in amount okay and then this will basically do kind of what we did we did here except we'll clean up the code a lot so if I come over here and I um grab pretty much all this uh let's just uh cut that and we'll paste it here for now so this is going to be the result um we should have another version of this that doesn't actually uh that actually modifies the existing one instead of having to create a uh another one but um I guess that's okay we will actually take in um an array of pixels the reason is that there are so many different types and I don't want to have to deal with the type of the image and then figure out um how to put that into that it's just a mess so we won't do that here uh we will have a result though and I guess if we do that then we need a width and height okay we'll make this work with um just default images I think cuz it's getting it's already getting a bit messy so we'll have the original uh get WID and get height over here and we'll make the new one in the form argb okay but they as you can see it's a it's in so over here we'll um we'll cast now the the old one again it was a data buffer in but that's not what we want anymore um what we want instead is something in the image package so I'm I was hoping to see what was in there because I don't know everything maybe this this will list the available ones nope looks like Google it is so java. image right was that is this where this is yes it is so let's take a look at this um data buffer bite is probably what it's going to be I mean I imagine um I was wondering if there was a special one for the uh inter Leed kind of BU variant but I guess it's not so we'll go ahead and cast that to that um and then we will uh obviously change this to be a bay and it's still it's still sad okay let's import that and it should be good now yeah so we don't need to do any of this anymore so we've got the uh so we've got the or so we' got the pixels these are the original pixels right so what we'll do is we'll brighten it by a set amount now what we don't have that we should have is a matthu tills class I'm sure we had something like this but looks like we don't um again this will be uh we're getting a lot of stuff done uh this will be again a um static kind of deal and the reason I'm doing this is I literally just want um a clamp uh thing and that's it okay so basically we have a value and we want to clamp it between a minimum and maximum so we're basically saying that um if uh if the value is less than minimum then just return minimum if the value is greater than maximum return maximum okay so it makes sure that the value that we fit into this will never be between it sorry will always be between minimum and maximum and never outside that so um basically all we have to do is we have to say that if value is uh less than minimum then we return minimum uh otherwise if value is greater than maximum return maximum otherwise uh we return value all right uh I could have probably written this as some kind of inline weird thing I'm not going to waste too much time on that and in fact since we are here I will actually make a uh public static um int Min so this will just return uh whichever one is smaller so if value is less than Min um sorry whichever one is uh yeah so we'll return Min otherwise it will return value okay so all this means is that if value is less than minimum then we'll return minimum okay because we don't want it to go beneath the minimum otherwise return value and we'll do the same thing for Max this is just a nice nice little methods to have as we start uh working with clamped values and whatnot value greater than Max then we'll return Max L value okay so we got some nice math details the reason I did that is uh because of something I'm about to show you now original do get height get width uh and then pixels and then original I'll get with Okay so we've got these we've separated the channels now what I'm going to do is I'm actually going to say that R is going to equal um math utils in fact I'm going to I don't want to write math details every time so I'm going to import it statically so if you type in import static um and then what was it com. theo. Rin do um util do mathutils do ASX it'll basically uh import every static method as if it was kind of in this class um or in this name space so what that means is that I can just basically call clamp instead of having to do math utils do clamp so it's quite nice um but basically all I'm going to do is it's going to be R plus amount so you can feed in a negative amount but I'm going to clamp that between 0 and 255 okay simple as that and uh I'm basically going to repeat that for the other ones as well so you can see how easy it is it makes sure it basically just lets us not have a bunch of if statements in here which would make everything really messy so that's nice uh now the result pixels okay uh result pixels uh will be um kind of the same deal except it looks like we're going to be using integers so it'll be a data buffer int okay and this will be uh result. get roster. getet buffer and uh we'll have change that to be int okay all good uh and then we'll set the result pixels to this and uh you can see that we can kind of keep exactly the same deal that we had before um and then we'll return a result okay so that should work um again I have never actually I haven't I haven't written this code and tried it out so I don't know if this will work that that's just what game programming is is uh is about unfortunately maybe fortunately cuz you get I guess you guys get to see me deug it but um I just don't have the time obviously to uh to not do that okay so image hover is now going to be image utils do change brightness [Music] um yeah I'll do I'll I'll rename this to like create brighter or something or create I don't even know I was going to say create brighter but you can make it darker so anyway um so original is image and amount we'll say 100 which is what we had before so it should look the same hopefully and not crash so we'll see what happens whoa that did not work oh of course it didn't work properly what was I thinking so this is different okay we can't actually do this now what we have to do is this assembly that we have here I'm not sure why I just ignore that I kind of just forgot this assembly here isn't actually this okay so int we'll have to we can do this in a bunch of different ways but we'll have some offset here and basically r is just going to be oh it's really annoying actually because it's a bite and bites are just terrible in Java um maybe we can cast it to an end and it'll work it probably won't oh I hate this bites in Java are worse are the worst cuz they're signed they're not unsigned oh okay let's just see what happens um so basically this will be pixels so we don't need this anymore so pixels we'll have to get all of them as well pixels basically offset Plus+ is what they'll be uh so this will be a the alpha channel so a BGR seems to be uh the the the the pro strategy um and it's literally just this okay well how did that happen must have hit control of course um it's just going going to be that right and then we can clamp them hopefully this actually converts them into an integers I really hope it will um we can uh clamp them between uh the values that we need and then we can um pop in uh a back in okay and maybe that'll work hopefully please work oh it made it darker no that didn't work almost worked I mean you know it didn't but it almost worked so now I'm going to open my browser and type in Java byte to int this is what I'm looking at not going to hide this from you guys oh really you can just do int value wow who knew it would be so easy I I hope this is the solution I'm kind of just looking at the first thing I see so we'll do this new bite you can see why Java might be slow because you need to create an object to convert it to an integer uh to one signed in uh that works for me uh is that a static there it's got to be static bi. two unsigned in oh this is going to be beautiful wait what else do they have there two unsigned yeah long okay hopefully this works uh the way I I want it to guessing that returns an end yep maybe maybe this isn't so bad after who knows maybe it's not so bad W okay please work yay okay it's not so bad I swear maybe they added this no they didn't it's apparently that's that's from 2012 at least so anyway yay look at that it works so uh now what we can do is we can go into um uh our player and we can actually increase or decrease the brightness let's try put it to like negative like 50 or something right you can see that darkens it now yeah pretty cool so you can change any image now okay it's pretty cool it's pretty powerful um you can literally change any image so um yeah so it's pretty it's pretty damn awesome um what was I going to say yeah so that will create a new one so change brightness will return uh I'll just make a little Java doc comment for the first time I think in this series that uh where is this supposed to go it kind of looks weird oh I'll just that's cuz I don't have the yay returns a new image just so people people know and by people I mean me um okay cool anyway uh that is pretty much it um I'm going to maybe wrap up the video there while I was going to but I remembered that I still need to do the other thing um and then one other thing I should mention is get rid of that one other thing I should mention is if you wanted to do one on like pressed or something so image pressed again because this is so easy now uh you can just do something like image press equal you can just see how much less code that is I mean it's you know it's Madness uh we can do something like that and then we can be like uh we'll override press uh and we'll set that equal to button do set image whoa what happened that I was holding control down when I clicked again whoops button do set image image pressed and I guess we'll also need released so released we'll set it back to our image I guess all right now we've got the whole the whole whole thing if we click you can see it goes brighter if we let go uh little close it but you can see if we click it goes brighter and then uh when we hover it goes darker or something so there we go we've got a pretty cool um thing going on and it's really simple to do as you can see so awesome I wonder we probably don't even need these because they are created on the Heap so hopefully the references will possess I have no idea because I'm not really an expert on how Java handles memory but um it is going to be a bit weird let's see if we can do this yeah we can okay I don't know where it's tracking those references but it is so it's best it's probably captured them um so everything's fine so we can actually get rid of these and we can do it the ultra risky way um this just feels weird to me but it's probably fine um because again they'll be they'll be sitting there somewhere and the garbage collector probably won't touch them hopefully I mean it might sometime in the future who knows it's Java but uh you can see that everything um works perfectly uh now if we click the mouse here we don't want to shoot okay um but yet but yet uh you can see that the way that our mouse works and the way that anything really works is that um we basically uh you can see that when we click and we check to see if if a button is clicked it doesn't matter anywhere in our window where we click we can query the get button and it will return that now the best way I can think of fixing that problem and by best way I really mean best way okay because um there are many ways you can fix that one way you could be like instantly you could just be like in the player class if the button position is you know if the button position X is greater than that than the beginning of that panel then just uh you know that's doesn't count as as pressing a button you could do something as simple as that and that will work well but the proper way to do it would be to have an actual kind of event dispatcher uh system right an event handling system so what that means is that you basically raise an event and everyone's everyone that is subscribed to that event in a certain layer stack order uh will receive um a uh an event uh call back so the there'll be like an onevent method or just an event method or whatever um and then that will get called whenever there's an event and then what happens there is you can actually return basically true or false true means that you have handled the event false means that you haven't handled the event um so if you're returning true it means that any other layers in your stack do not receive that event so in other words in our stack this panel would be uh higher in the stack than the rest of the game because you can see it is literally on top of it um so we process the events for that first even though we render it in reverse order um and then what happens is we uh when we click here we say that obviously if we have clicked and we've notified that the click has been inside the panel then we basically return true from that event uh handling method which means that uh other other layers behind it won't actually receive the event because otherwise if we return false the event dispat will send it to the next uh layer in the stack and it will keep going so that's basically a quick overview of how an event dispatcher would work and um this is more or less how you would handle it in the real world um so if this was a real game uh that's how we would do it excuse me um so if you guys want to see that it's a bit complicated it's not really complicated it's actually really simple but it's going to take like maybe two episodes or three episodes to do um and since this series is all about involving you guys I am asking you if you want to see that if you would rather see the mini map and we just go on with this and then just basically put a put in a hack that says that if the mouse pointer is uh if the x is greater than the panel then ignore it uh then um yeah we could do something like that instead like and again that will literally be as simple as just saying um where we do the uh update shooting I think right uh if okay so first of all I don't even know what the x is so it's like 660 so if that is greater than 660 return okay and then suddenly look he doesn't shoot anymore when we when we're over here I'm clicking you can see I just closed the game or I uh or I clicked on the Hello button several times and uh you can see he's not shooting and then he does when when you're here so you can see that you could do something as simple as that and that'll work but if you guys want to see a bit of a professional is I guess uh implementation of a layer stack not that it's really professional or anything but um I I just mean that um the proper way to handle this then let me know in the comments below and I will pay attention to that so that's going to pretty much wrap up this video as always you can support me on patreon if you like uh and for pledging $5 a month if you pledge $5 or more per month then you get access to all of the source code from game programming and it's all versioned so the cool thing about that is you can actually go to GitHub and you can see exactly the lines of code that I've changed uh with each episode which is awesome um so you don't have to uh worry too much about that um yeah thanks for watching guys um I hope you enjoyed if you did please hit the like button and I'll see you guys next time goodbye [Music]

Original Description

Source Code ► https://www.patreon.com/thecherno Twitter ► http://www.twitter.com/thecherno Stream ► http://www.twitch.tv/thecherno Website ► http://www.thecherno.com Facebook ► http://www.facebook.com/thecherno Want more? You can help out by supporting me on Patreon! https://www.patreon.com/thecherno ------------------------------------------------------------------------------------------------- In this video: - How to make a game - How to change an image's brightness ------------------------------------------------------------------------------------------------- Website: http://www.thecherno.com Twitter: http://www.twitter.com/thecherno Facebook: http://www.facebook.com/thecherno Subreddit: http://www.reddit.com/r/thecherno/ Steam Group: http://www.steamcommunity.com/groups/thecherno ------------------------------------------------------------------------------------------------- Outro music is by Approaching Nirvana: http://www.youtube.com/approachingnirvana
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from The Cherno · The Cherno · 0 of 60

← Previous Next →
1 3D Game Programming - Episode 1 - Window
3D Game Programming - Episode 1 - Window
The Cherno
2 3D Game Programming - Episode 2 - Game Loop
3D Game Programming - Episode 2 - Game Loop
The Cherno
3 3D Game Programming - Episode 3 - Arrays
3D Game Programming - Episode 3 - Arrays
The Cherno
4 3D Game Programming - Episode 4 - Drawing Pixels!
3D Game Programming - Episode 4 - Drawing Pixels!
The Cherno
5 3D Game Programming - Episode 4.5 - How Rendering Works
3D Game Programming - Episode 4.5 - How Rendering Works
The Cherno
6 3D Game Programming - Episode 5 - Playing with Pixels!
3D Game Programming - Episode 5 - Playing with Pixels!
The Cherno
7 3D Game Programming - Episode 6 - Performance Boosting
3D Game Programming - Episode 6 - Performance Boosting
The Cherno
8 3D Game Programming - Episode 7 - FPS Counter
3D Game Programming - Episode 7 - FPS Counter
The Cherno
9 3D Game Programming - Episode 8 - Alpha Support and More
3D Game Programming - Episode 8 - Alpha Support and More
The Cherno
10 3D Game Programming - Episode 9 - Beginning 3D
3D Game Programming - Episode 9 - Beginning 3D
The Cherno
11 3D Game Programming - Episode 10 - Floors and Animation
3D Game Programming - Episode 10 - Floors and Animation
The Cherno
12 3D Game Programming - Episode 11 - Rotation
3D Game Programming - Episode 11 - Rotation
The Cherno
13 3D Game Programming - Episode 12 - User Input
3D Game Programming - Episode 12 - User Input
The Cherno
14 3D Game Programming - Episode 13 - Render Distance Limiter!
3D Game Programming - Episode 13 - Render Distance Limiter!
The Cherno
15 3D Game Programming - Episode 14 - Basic Mouse Movement
3D Game Programming - Episode 14 - Basic Mouse Movement
The Cherno
16 3D Game Programming - Episode 15 - Textures + More!
3D Game Programming - Episode 15 - Textures + More!
The Cherno
17 3D Game Programming - Episode 16 - Walking, Crouching, Sprinting + More
3D Game Programming - Episode 16 - Walking, Crouching, Sprinting + More
The Cherno
18 3D Game Programming - Episode 16.5 - Exporting Runnable Jars
3D Game Programming - Episode 16.5 - Exporting Runnable Jars
The Cherno
19 3D Game Programming - Episode 17 - Small Adjustments + Birthday!
3D Game Programming - Episode 17 - Small Adjustments + Birthday!
The Cherno
20 3D Game Programming - Episode 17.5 - Creating an Applet
3D Game Programming - Episode 17.5 - Creating an Applet
The Cherno
21 3D Game Programming - Episode 18 - The Beginning of Walls
3D Game Programming - Episode 18 - The Beginning of Walls
The Cherno
22 3D Game Programming - Episode 18.1 - A Few More Things
3D Game Programming - Episode 18.1 - A Few More Things
The Cherno
23 Episode 18.5 - Creating an EXE File in Java
Episode 18.5 - Creating an EXE File in Java
The Cherno
24 3D Game Programming - Episode 19 - Rendering Walls
3D Game Programming - Episode 19 - Rendering Walls
The Cherno
25 3D Game Programming - Episode 20 - Continuing Walls, Fixing Bugs, and Managing Crashes
3D Game Programming - Episode 20 - Continuing Walls, Fixing Bugs, and Managing Crashes
The Cherno
26 3D Game Programming - Episode 21 - Texturing Walls, Fixing Clipping, and Fixing the Mouse
3D Game Programming - Episode 21 - Texturing Walls, Fixing Clipping, and Fixing the Mouse
The Cherno
27 3D Game Programming - Episode 22 - Random Level Generator + Properly Fixing Clipping
3D Game Programming - Episode 22 - Random Level Generator + Properly Fixing Clipping
The Cherno
28 3D Game Programming - Episode 23 - Graphical User Interface (GUI) Launcher
3D Game Programming - Episode 23 - Graphical User Interface (GUI) Launcher
The Cherno
29 3D Game Programming - Episode 24 - Making Our Launcher Work
3D Game Programming - Episode 24 - Making Our Launcher Work
The Cherno
30 3D Game Programming - Episode 25 - Writing and Reading Files
3D Game Programming - Episode 25 - Writing and Reading Files
The Cherno
31 3D Game Programming - Episode 26 - Custom Resolutions
3D Game Programming - Episode 26 - Custom Resolutions
The Cherno
32 3D Game Programming - Episode 27 - Decorating the Launcher
3D Game Programming - Episode 27 - Decorating the Launcher
The Cherno
33 3D Game Programming - Episode 28 - Continuing our Custom Launcher!
3D Game Programming - Episode 28 - Continuing our Custom Launcher!
The Cherno
34 3D Game Programming - Episode 29 - Launching The Game
3D Game Programming - Episode 29 - Launching The Game
The Cherno
35 3D Game Programming - Episode 30 - Colour Processing In-Depth
3D Game Programming - Episode 30 - Colour Processing In-Depth
The Cherno
36 3D Game Programming - Episode 31 - Sprites!
3D Game Programming - Episode 31 - Sprites!
The Cherno
37 3D Game Programming - Episode 32 - Sprite Mapping
3D Game Programming - Episode 32 - Sprite Mapping
The Cherno
38 3D Game Programming - Episode 33 - High Resolution Rendering
3D Game Programming - Episode 33 - High Resolution Rendering
The Cherno
39 3D Game Programming - Episode 34 - Entities
3D Game Programming - Episode 34 - Entities
The Cherno
40 Genesis - My Game for Ludum Dare 24
Genesis - My Game for Ludum Dare 24
The Cherno
41 Vlog + Ludum Dare Results
Vlog + Ludum Dare Results
The Cherno
42 Game Programming - Episode 1 - Resolution
Game Programming - Episode 1 - Resolution
The Cherno
43 Game Programming - Episode 2 - Threads
Game Programming - Episode 2 - Threads
The Cherno
44 Game Programming - Episode 3 - Game Loop
Game Programming - Episode 3 - Game Loop
The Cherno
45 Game Programming - Episode 4 - Window
Game Programming - Episode 4 - Window
The Cherno
46 Episode 5 - Buffer Strategy
Episode 5 - Buffer Strategy
The Cherno
47 Game Programming - Episode 6 - Graphics Initialized
Game Programming - Episode 6 - Graphics Initialized
The Cherno
48 Game Programming - Episode 7 - Buffered Image and Rasters
Game Programming - Episode 7 - Buffered Image and Rasters
The Cherno
49 Game Programming - Episode 8 - The Screen Class
Game Programming - Episode 8 - The Screen Class
The Cherno
50 Game Programming - Episode 9 - Rendering Pixels
Game Programming - Episode 9 - Rendering Pixels
The Cherno
51 Game Programming - Episode 10 - Clearing the Screen
Game Programming - Episode 10 - Clearing the Screen
The Cherno
52 Game Programming - Episode 11 - "Out of Bounds, Baby!"
Game Programming - Episode 11 - "Out of Bounds, Baby!"
The Cherno
53 Game Programming - Episode 12 - Negative Bounds
Game Programming - Episode 12 - Negative Bounds
The Cherno
54 Game Programming - Episode 13 - Timer
Game Programming - Episode 13 - Timer
The Cherno
55 Game Programming - Episode 14 - FPS Counter
Game Programming - Episode 14 - FPS Counter
The Cherno
56 Episode 15 - Tiles
Episode 15 - Tiles
The Cherno
57 Game Programming - Episode 16 - The Map
Game Programming - Episode 16 - The Map
The Cherno
58 The Walls 2 - Minecraft PvP Survival Map
The Walls 2 - Minecraft PvP Survival Map
The Cherno
59 Game Programming - Episode 17 - Key Input
Game Programming - Episode 17 - Key Input
The Cherno
60 Game Programming - Episode 18 - Controlling The Map
Game Programming - Episode 18 - Controlling The Map
The Cherno

This video teaches how to modify image brightness in game programming using Java, covering concepts such as image processing, color channels, and byte array manipulation. It also touches on event handling and software development.

Key Takeaways
  1. Print the type of the image
  2. Access a particular color channel using byte array indices
  3. Create a new image by modifying the brightness of the original image
  4. Import static methods from mathutils
  5. Clamp brightness between 0 and 255
  6. Use integers for result pixels
  7. Convert bytes to integers using byte to int conversion
  8. Implement an event dispatcher system
  9. Raise an event and subscribe layers to receive a callback
💡 Modifying image brightness in Java can be slow due to object creation, but using unsigned integers can improve performance.
Up next
George Hotz | Programming | tinygrad, starting on CLOUD=1 | Part 2
george hotz archive
Watch →