Forum Replies Created
-
AuthorPosts
-
Image is a bit more than a convenience wrapper – without it, you can’t ‘draw’ pixmaps so it’s pretty important!
pmAlpha parameter for Pixmap.Load will leave the loaded pixmap alone if false, but will premultiply pixmap colors by pixmap alpha if true. In either case, pixmap alpha values are not modified.
So if you just want to load the pixmap as it is stored on disk without modifying colors, set pmAlpha to false (or just leave it off as it defaults to false).
If you do this but are also planning on creating an image with the pixmap, you should use pixmap.PremultiplyAlpha() at some point *before* creating the image. For example:
Monkey123456789101112'Load 'plain' pixmap without any fancy pants alpha premultiplyingLocal pixmap:=Pixmap.Load( "mypixmap" )'Do my amazing thing to the pixmapMyAmazingPixmapModifier( pixmap )'PremultiplyAlpha because we want to create an image with it.pixmap.PremultiplyAlpha()'Create an imageLocal image:=New Image( pixmap )In other words, New Image( pixmap ) always assumes you have premultiplied alpha somehow.
Ok, I’ve hacked up yet another approach to all this. This attempts to duplicate unity’s system in that matrix/hierarchy are stored in a Transform component that is present in all game objects. It implements the transform component using a dummy entity. Any camera, light and model etc components use this dummy entity as a parent for their internal mojo3d entties.
The actualy entities involved are *never* publicly available so there’s no chance of the hierarchy being broken/rearranged behind your back or any other other weirdness happending. Also, I’ve added signals for ALL property setters just for the hell of it.
It doesn’t look too bad to me. There’s a certain amount of work involved adding wrappers for everything, but there aren’t that many entities so IMO it’s doable. Transform will probbly be the trickiest as that’s how you move things around etc. But lots of that stuff is in an extension class that can be copied/pasted too.
The coolest thing about this IMO is that GameObject/Component are 100% ‘clean code’. There are no dependancies on how mojo3d or Entity works (or doesn’t!).
Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225Alias Mojo3dCamera:mojo3d.graphics.CameraAlias Mojo3dLight:mojo3d.graphics.LightAlias Mojo3dModel:mojo3d.graphics.ModelClass GameObjectMethod New()New Transform( this )EndMethod GetComponent<T>:T( name:String )Return _components[name]EndInternalProperty Components:StringMap<Component>()Return _componentsEndPrivateField _components:=New StringMap<Component>EndClass ComponentMethod New( gameObject:GameObject,type:String )_gameObject=gameObject_type=type_gameObject.Components[_componentType]=SelfEndProperty GameObject:GameObject()Return _gameObjectEndProperty Type:String()Return _typeEndPrivateField _gameObject:GameObjectField _type:StringEndClass Transform Extends ComponentField ParentChanged:Void()Field MatrixChanged:Void()Field Moved:Void()Method New( gameObject:GameObject )Super.New( gameObject,"transform" )_entity=New Entity_entity.SetDynamicProperty( "component",Self )EndProperty Parent:Transform()Return _parentSetter( parent:Transform )If parent=_parent Return_entity.Parent=_parent ? _parent._entity Else Null_parent=parentParentChanged()EndProperty Matrix:Mat4f()Return _entity.MatrixSetter( matrix:Mat4f )If matrix=_entity.Matrix Return_entity.Matrix=matrixMatrixChanged()EndMethod Move( v:Vec3f )_entity.Move( v )Moved()EndInternalProperty Entity:Entity()Return _entityEndPrivateField _parent:TransformField _entity:EntityEndClass Camera Extends ComponentField FOVChanged:Void()Method New( gameObject:GameObject )Super.New( gameObject,"camera" )_camera=New Mojo3dCamera( gameObject.GetComponent<Transform>().Entity )EndProperty FOV:Float()Return _camera.FOVSetter( fov:Float )If fov=_camera.FOV Return_camera.FOV=fovFOVChanged()EndPrivateField _camera:Mojo3dCameraEndClass Light Extends ComponentField TypeChanged:Void()Method New( gameObject:GameObject )Super.New( gameObject,"light" )_light=New Mojo3dLight( gameObject.GetComponent<Transform>().Entity )EndProperty Type:LightType()Return _light.TypeSetter( type:LightType )If type=_light.Type Return_light.Type=typeTypeChanged()EndPrivateField _light:Mojo3dLightEndClass MeshRenderer Extends ComponentField MeshChanged:Void()Field MaterialChanged:Void()Method New( gameObject:Object )Super.New( gameObject,"meshRenderer" )_model=New Mojo3dLight( gameObject.GetComponent<Transform>().Entity )EndProperty Mesh:Mesh()Return _model.MeshSetter( mesh:Mesh )if mesh=_model.Mesh Return_model.Mesh=meshMeshChanged()EndProperty Material:Material()Return _model.MatrialSetter( material:Material )If material=_model.Material Return_model.Material=materialMaterialChanged()EndPrivateField _model:Mojo3dModelEndI don’t know if I’lll be adding Moved/Rotated/Scaled signals. I think (a bit like Layout) changes to entity matrices are much better dealt with in one ‘hit’ in one phase. It can take game logic several moves/rotates etc to update an entity, and if each step triggers an OnMove (and possibly child OnMove recursively etc) it can add up.
Entity does in fact have a (currently hidden) Seq:Int property that is incremented when entity matrix is modified. This is actually used by physics to update bullet data if necessary just before World.Update(). A game engine could do the same.
I think this is partly why I’m nervous about using Entity as GameObject. There is not real control over what can be done to the entity – it’s kind of like having a public field. Unless I add a signal to *every* setter and potentially modifying method, there is just no sane way to tell what has been done to the entity.
On the other hand, if all operations go through a GameObject or Component wrapper and the underling enties are private fields, the wrapper knows exactly what’s going on, fire off signals, call virtual methods and generally do whatever it needs to do. It can ‘redesign’ the entity API, add new methods, hide unwanted ones etc. Yes, there’s a fair bit of crappy work involved, but the win is 100% control over the underlying entity.
It’s definitely a compiler bug, would you mind posting an issue at github?
Actually, I quite like the ComponentBox idea – it does provide a way to add fields to a class via class extension anyway.
One think I have added to Entity that may be of use here is:
Monkey1234SetDynamicProperty<T>( name:String,value:T )GetDynamicProperty<T>:T( name:String )Very simple, but I think it should be very useful.
I am using this to store the RigidBody for an entity in the entity itself (similar to a component I guess). To date, while you have been able to do ‘rigidBody.Entity’, you haven’t been able to do the opposite, ie: ‘entity.RigidBody’. Since I want to keep physics in an optional module, Entity may not necesarilly know about RigidBody. I didn’t want to go for a full blown Component system here, because I haven’t need it – everything works except for entity.RigidBody and this fixes that.
But the dynamic property stuff is also there for general use and it would be entirely possible to use it for a ComponentBox, eg:
Monkey1234567891011Function GetComponentBox:ComponentBox( entity:Entity )Local cbox:=entity.GetDynamicProperty<ComponentBox>( "cbox" )If Not cboxcbox=New ComponentBoxentity.SetDynamicProperty( "cbox",cbox )EndifReturn cboxEndThis is, of course if you *really* want to use Entity as *the* GameObject type. I’m not sure this is a such good idea, but I think I’m basically just gonna sit this one out and watch what you come up with as I don’t have a lot of experience here.
Another thing with the component virtual methods, with the ComponentBox approach it ‘s kind of a non-issue in a way. For example:
Monkey123456789101112131415161718192021222324252627282930Class ComponentBoxField _components:Stack<Component>EndClass ComponentVirtual OnUpdate() VirtualEndEndClass Entity ExtensionMethod GetComponentBox:ComponentBox()'..uses GetDynamicProperty here...maybe protected/private too?EndMethod GetComponents:Stack<Component>()'...maybe protected/private?EndMethod Update()For local c:=Eachin GetComponents()c.OnUpdate()NextEndEndTherefore, calling entity.Update() will call all virtual Component.OnUpdate methods. You can’t override Entity.Update, but the point here is to not have to extend Entity anyway, but use Component instead, right?
Another thing that may help is the ‘signals’ in Entity, ie:
Monkey12345Field Copied:Void( copy:Entity )Field Destroyed:Void()Field Hidden:Void()Field Shown:Void()These are ‘hooked’ by RigidBody and could be by ComponentBox too, eg:
Monkey12345678910111213141516171819202122Class ComponentBoxField _entity:EntityField _components:=New Stack<Component>Method New( entity:Entity )_entity=entity_entity.Destroyed+=Lambda()For Local c:=Eachin _componentsc.OnDestroyed() 'call to component virtual methodNextEndEndEndAgain though, this assume Entity *is* your GameObject which for some reason makes me hella nervous…but please ignore me as this is well outside my comfort zone.
Very keen to see what you come up with!
if ALPHA channel is ZERO i can still the color. To fully hide pixel i need to set ALPHA to zero and RGB to zero also.
This is because image rendering uses pre-multiplied alpha. This is a technique where image colors are assumed to be pre-multiplied by image alpha – more information here (and much more via goggle):
You can premultiply pixmap data like this by setting the pmAlpha parameter of Pixmap.Load to true when loading a pixmap, or using the Pixmap.PremultiplyAlpha method.
Note that Image.Load is really just a ‘wrapper’ around something like this:
Monkey1234Local pixmap:=Pixmap.Load( path,Null,True )Local image:=New Image( pixmap )Return imageIf you want to modify image pixels when loading, the best way to do it is to use Pixmap.Load as above, modify the pixmap, then use New Image to create anew image with the modified pixmap.
Image are not really intended to be ‘read’ by the CPU. In fact, the more HW evolves, the harder this gets – in Open GL ES there aren’t even any commands for reading texture data, so you need to render and then copy from the backbuffer! The has the potential to lose lots of precision along the way, as textures/backbuffers masy be in a crappy format behind the scenes on some taregets and texture data may be compressed etc etc.
The only way to guarantee ‘clean’ pixele data is by using Pixmap.Load and using the pixel data *before* it reaches the image/texture. Once things reach the GPU, they should ideally only be read by the GPU – which includes shaders, which can easily access texture data (although again it may not be exactly the same as the original pixmap data on some targets).
Yes, modifying the manifest is the correct way to do this in monkey2.
would it be a good idea for Class Extensions to allow adding fields and virtual methods?
It’d be brilliant! However, it’s also pretty much impossible in a compiled language like monkey2. Adding fields changes the size of the object and adding virtual methods changes the size of the virtual function table. Both need to be fixed for ‘New’ to work. Offsets of fields/methods would also clash like crazy between modules. This is only really possible in a dynamic language like python/javascript etc.
Currently I have a GameObj class, and since it can contain any Mojo3D entity, I can turn a GameObj into anything. But I have to have components for all that, like a “LoadModel” or “LoadSprite” component that only kicks in at the game start.
I have no idea what you’re talking about here sorry! What exactly would you like done to mojo3d?
I’m certainly into exploring ideas here, and I think there may be some overlap with several problems I’m yet to solve, but I just want to make sure we’re on the same page. From the above, it sounds more to me like you’re talking about a ‘scripting’ system what with all the loading going on!
Perhaps post some hypothetical sample code, ‘making up’ any methods you’d like to see added?
I have no desire to turn mojo3d into a component system, it’s very lightweight and I like it like that.
I’m not even 100% what you’re try to achieve here anyway. Do you want to make Entity final and implement cameras, lights, models, etc via components instead of subclassing? The way Unity does it, even entity transform is not part of entity – you want to do this too?
Not sure what you mean by a MaskTexture here – is this like storing the alpha channel in a separate texture?
But the idea is/was that if you want to use a different shader with an image, you need to specify it when constructing or loading the Image. You could also do things like add Image.LoadMasked() style class extensions.
A quick thought though: Image is not really designed for extension the way mojo3d’s material is. Maybe it should be?
Material has a protected SetShader method so subclasses (like PbrMaterial and WaterMaterial) can change their shader ‘on the fly’ if necessary. The idea is that material will eventually have a protected InvalidateShader() method, and a protected virtual OnValidateShader:Shader() method. InvalidateShader() would be invoked when certain properties are modified, and OnValidateShader() would return different shaders depending on material property values. For example, if a material’s NormalTexture property is null, OnValidateShader() could return a non-bumpmapped variation of its shader. A lot of this is just theory though and has not been implmented yet. I’m kind of afraid it might be overkill, and will just be too complex to be useful.
In this case, Material.Shader is not writeable as this defeats the purpose of giving material subclass control over the shader. That said, it would be possible to write a CustomMaterial subclass or similar that did allow you to write Shader.
Image could work in a similar way, or perhaps even subclass Material too.
Yes, it’s possible, although to be honest I can’t see why you’d want to change shader on the fly.
I do tend to make things read only by default if there doesn’t seem to be an obvious reason to allow them to be writeable. I find this generally keeps object logic much simpler and often allows for future optmizations.
[edit]Pushed to develop branch![/edit]
I’ll add SetInt if you want – just post an issue to github to remind me!
Mojo3d and company are now fully part of monkey2 and aren’t going anwhere. Will change Patreon page ASAP.
The main reason Patreon has taken a dive is because super mega patron Impixi has bowed out. I knew this was coming though, we talked about it back when mojo3d was started and it was understood he’d only be able to donate so generously until near end of year-ish.
So thanks Impixi! I’vegot mojo3d off the ground thanks to your help and I hope it develops into something way cool from here on in!
But hey, Patrepon’s still at $414 so monkey2 is still very much in business (alhough I may have to look at rasing funds some other ways too).
Never noticed that before but I’m sure it can be cleaned up!
-
AuthorPosts