Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

  • Days Won


noizex last won the day on September 30 2018

noizex had the most liked content!

Community Reputation

1450 Excellent

About noizex

  • Rank

Personal Information

  • Role
    Creative Director
  • Interests


  • Twitter

Recent Profile Visitors

11824 profile views
  1. Shouldn't this be: (power + 2.0f)/(4.0f*PI*( 2.0f-exp2(-power / 2.0f))) ? These equations mention exp2 while you just multiply there, which has quite different effect...
  2. noizex

    Official SVN repo down?

    Yeah it's back now - haven't looked there for a while and wasn't sure if that's not long term. Thanks for reply.
  3. noizex

    Official SVN repo down?

    Hi, Is it temporary or it's been like this for a while? I can't access the SVN repo (http://svn.code.sf.net/p/angelscript/code/trunk). Anyone knows anything? How automated is the GitHub mirror? It seems to have last change 3 months ago which seems quite old, and I can't compare this to Subversion one because ^.
  4. Okay seems like new GD.net editor makes it not possible to easily split quotation into sections and reply below each one, so I will reply in a different way re "sounds quite interesting, how complex is your "pipeline" ? do you have transformfeedbacks and other "non-trivial" routines" - it's not very complex I'd say, but capable of any thing that I'd throw at it, and pretty flexible. I don't use TF right now, but I definitely will use compute shaders, and this will happen on "pass" stage - which is way too broad a topic to cover here. Basically all buffer handling happens either on resource load stage (vertex and index buffers for meshes) or on render/pass stage (filling uniform buffers and SSBOs with data each frame, or with material data whenever new material is loaded). Think of it this way: render queue provides all types of geometry to render, passes consume these items as they need (UI pass will consume 2d geom, alpha tested pass will render only alpha tested meshes etc.). If I need to put compute or transform feedback into it, it will happen on pass stage as well. re "different programs have different sets of "per-object-uniforms" (which is the reason for my 2 different structs that have about the same purpose). would you suggest to kind of use a "data-driven" approach (i hope thats the right word) meaning that i just have 1 struct with all possible per-object-uniforms for all programs? (redundand data)" That's something I wondered too. By going into UBOs/SSBOs you abandon easy way to freely define uniforms however you like, and you need to be more strict. Are you sure you need all these params, and if so, are they properties of materials? Or objects/meshes themselves? The way to have highly performant uniform buffers and indirect drawing later is to be pretty strict about these things, and it may pay off to rethink the approach. For example I ended up having very simple "per object" uniforms (matrices, material id, bone id if applicable) and these id types index into other uniform arrays (these can be smaller than max number of objects, mind it). So for things that control rendering I have material definitions with all needed properties etc. In the end you probably end up not needing that much unique properties per different "objects". re "egarding buffers, i dont mess with them anywhere else but in the renderer.cpp, since there is no reason to have as many buffers as objects. i have ALL meshes (of the same vertex type) in 1 buffer laid end to end. (of course thats only possible for static meshes)" That's definitely a good thing to have.
  5. First question: why you need two different types of structs to hold pretty similar data? Both cases require vertex array id, program id, primitive type, buffer ids etc. This means you could just have one "render item" struct that holds generic data about every mesh you want to draw. This allows further to store them in an efficient way and sort based on some criteria that would minimize the number of draw calls required. Remember - on this level it's all mesh drawn with some set of resources. If you need specific treatment for different meshes (like split drawing 2D/UI and regular 3D geometry, or have transparent geometry processed differently) you can create "lists" or "queues" which hold these uniform render items and can be processed on their own. For more read about these topics just use search on these forms for mentioned keywords ("render queue", "render items/atoms/tasks") and you will get plenty of very interesting topics where a lot of clever people described how they do this kind of stuff. Main and most known article about this, which is mostly focused on sorting these items is: http://realtimecollisiondetection.net/blog/?p=86 I think the main question you have to answer is what kind of granularity and how many levels of abstraction of render chunk you need - in initial post you mentioned Nodes but also DrawRangeElementsBaseVertex struct which seems like something that could be merged together and have it created by higher level rendering layer (the one that knows which meshes to draw per game object). So instead of having these two layers just combine them into one that has all the info - base per-mesh uniforms (matrices, material properties), textures, vertex/index buffers, primitive types etc. I can quickly describe what I have and what works fine for me, though by no means treat it as some kind of "best solution" - far from it. I have 3 layers - 1. HIGH LEVEL INTERFACE which is directly accessed by my game logic, which contains container classes like StaticMesh, AnimatedMesh, BillboardMesh etc. These objects hold information such as Resource<Mesh> (which holds buffer ids etc.), Transform, visibility (drawn or not), and some specific logic like transforming mesh into another, having shape keys (morph targets) etc. There are two main roles for this layer: a) It interfaces with game logic so I can affect the state of these objects from within my scripts, enabling, disabling, changing parameters as I need it. (scripting) StaticMesh@ baseMesh("modelfile", transform); baseMesh.effect = "outline"; baseMesh.enabled = false; BillboardMesh@ tree("tree_sprite", transform); b) From Renderer perspective, these objects belong to rendering system and are iterated each frame to construct lower level render tasks. Basically these objects know what to do to produce a 1..N render tasks that are required to "draw" them. (C++, render_system.cpp) for (auto& mesh: staticMeshes_) { mesh.render(renderQueue); } (C++, static_mesh.cpp) void render(RenderQueue& queue) { for (auto& mesh: model->getSubmeshes()) { RenderTask task; task.vertexBuffer = mesh.vertexBufferId; task.indexBuffer = ... task.primitiveType = TRIANGLES; # and so on... queue.submit(SCENE_OPAQUE_GEOM, task); } } 2. MID LEVEL - render queues and render tasks. So each frame renderer iterates existing objects (StaticMesh, AnimatedMesh, BillboardMesh) and collects RenderTasks from them. Each RenderTasks contains all the information needed to render some mesh and each object can create as many as it needs to "render itself". One important thing to note is that these tasks have nothing to do with draw calls YET. These tasks are then added to various queues - opaque scene geonetry, alpha tested geometry, skybox, 2D UI, shadow map etc - these lists are later processed by different "passes". 3. LOW LEVEL (OpenGL calls) - once I construct queues and they're filled by render tasks, I begin various processing, and this heavily depends on passes that I have (which are another topic). Basically each pass may request one or more queues to "yield" their tasks (this does not result in clearing queue, so various passes can iterate over same sets of tasks) in a sorted way according to some sort key and algorithm. Based on this range of items, I perform batching which is done per-pass as different passes may batch differently. This means my sorted render tasks are processed one by one and I construct final draw call structs. This allows me to do things like - for 100 submitted render tasks, if they're all using same shader and buffers, I can stuff it all into a single indirect draw call. So the result of third layer is to produce draw calls - indirect calls, instanced calls, single calls - all based on criteria of sorting and batching. Also on this level I not only have draw call commands but also state changes needed - setting current program or vertex buffers. So it's an ordered stream of commands which are then pushed onto GPU one after another. Worth noting is - it's not the top level interface that decides there should be SET_PROGRAM command, but the mid tier, and only after processing things through the batcher. This is needed because top level does not have information needed to properly decide on state changes and would cause a lot of unnecessary state changes, so I derive these commands only from the batcher which knows when program needs to change to another one. Basically state changes equal batch break in this case, so I have usually as many batches as state changes (buffers + programs + render states) combined. Output of stage 3 is simple array of commands, that is then executed by GL context. It works pretty well so far and allows me to batch things like Sponza scene into just few indirect calls more or less automatically. I just submit all submeshes and let the system handle it. Let me know if you have any questions.
  6. Not sure what you're really asking, you pasted some source that doesn't really tell much - like what's your DrawableGeometry vs DrawableNode? What's the problem of doing it in one loop? Have you read about render queues, render items, sorting, state caching etc?
  7. noizex

    Moving to Game Programming industry

    I was having the same thoughts, having 15+ years of professional experience but in web development & e-commerce. Always wanted to make games, and I'm pushing my hobby project forward, slowly. Every now and then I have these thoughts that I'd like to work for game industry, but then I read/hear some impressions about how it looks like, and not even counting barriers to entry (my experience will probably not mean much, which means way lower negotiating position when it comes to salary), I feel that maybe I should stay where I am So just as you, I can't afford starting from the scratch, and I have kid & family too - so I need as much time as possible for my personal life too, which doesn't seem to go along with the "working culture" in game dev. Maybe I'm wrong, but it all seems to not be up to what I'm used to in web dev - both salary and time-wise. Maybe I should just sit on the edge of this and enjoy doing my project rather than get involved into "real thing" and regret. Sorry for not helping, just wanted to share I'm in similar mood from time to time and haven't really figured it out yet
  8. noizex

    how is character creation usually done?

    I think that's how it's usually done. I managed to set this in Blender using drivers, and it kind of worked, then exported this as "shape key" data and did vertex morphing in my engine. Proof of concept worked, I think it poses a lot of challenges when it comes to armour because armour has to scale with the body properly, which I think means you have the same amount of sliders and you work with 2 extremes for armour too? For face it's probably more suitable to use bones instead of morph targets.
  9. *SOLVED* This forum becomes sometimes my rubber duck.. I don't know how I missed that... I forgot the fact that when passing reference to a method, it's addRef'd, but then release is up on the user. So it was addRefing when passing CollisionObject to RigidBody constructor... I had this in my RigidBody. And when I removed it to "not affect" the CollisionShape - I removed both - unnecessary AddRef but also Release, the one that will zero the ref count in the very end... class Rigidbody { Rigidbody(CollisionObjectProxy* collisionObject, ...) { collisionObject_ = collisionObject; collisionObject_->addRef(); // <<<<<<-------- THIS IS NOT NEEDED BECAUSE ANGELSCRIPT ALREADY ADDREF'D COLLISION OBJECT // WHEN IT WAS PASSED TO RigidBody() script constructor } ~RigidBody() { collisionObject->release(); } } and was doing this: asCHECK(engine->RegisterObjectBehaviour("RigidBody", asBEHAVE_FACTORY, "RigidBody@ f(Transform@, CollisionShape@, float)", asMETHOD(DynamicsWorld, makeRigidBody), // ^^^^^^^^^^^^^^^ addRef, but release up to user which created RigidBody(...) It's actually in documentation (https://www.angelcode.com/angelscript/sdk/docs/manual/doc_obj_handle.html) but it wasn't about constructing CollisionShape, it was about passing it to other constructor. I will try to create some refadd/release flow for AS, maybe it helps others too, as it's sometimes easy to miss when script does something for you and when it wants you to do something...
  10. I tried to make a simplified test case and it's getting weird... In the test case it does not do this additional addRef which causes the trouble: So it seems that it DOES work as expected even when using factory global function, so something must be wrong in my code that causes this addRef
  11. SOLVED BY RUBBER-DUCKING @WitchLord, one quick idea that made me wonder - the only difference is creation through global "factory function", not factory itself - isn't it like: for factory behaviour, AS does not increase refcount on top of what it does for handling of the call, because it assumes user is setting refCount to 1 when returning new object - but global function does not assume this, and it additionally increases refCount of the object returned from it? So we end up with 1 refcount from constructor and 1 refcount from Angelscript, even though we don't want it because method is acting like factory and already returned refcount 1? That's why I had idea to initially set it to 0 for creation from method and not factory behaviour, but the order in which it happens is: ++, --, ++, RETURN which meant that if we 0++, then 1-- it ends up deleting itself. I think I can't do much because once I return that object from my C++ makeBox(), it's then processed by AngelScript. Andreas, can you confirm the above behaviour for registered global function that would increase refcount when returning something declared like this? And that its indeed different than factory behaviour? asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeBox(const vec3 &in)", asMETHOD(CollisionShapeFactory, makeBox), asCALL_THISCALL_ASGLOBAL, this)); I guess it totally make sense for non-factory type of functions, especially when Foo@ is a script object (this has to happen because on script side you have no way to increase refcount), but if FooCpp@ is actually on C++ side we can do this manually when returning the object. Most of the time we also want this, but not for factory functions. How to work around it when one can have more factory methods and not necessarily just create through constructor. Here I'd actually need "CollisionShape@-" kind of thing it seems. I wanted to make it explicit by the func name what's created: makeBox, makeSphere, makeCapsule because if I did it thorugh ctor it would not be encapsulated and have to be more in way of CollisionShape(Shapes::Box, boxparam1, boxparam2) which is not really good and can cause problems if user mismatches params & type enum. So the possibility to have global factory functions not registered as behaviour would be great. Although according to the docs this should be possible: A function that creates an object and returns it to the script engine might look like this: // Registered as "obj@ CreateObject()" obj *CreateObject() { // The constructor already initializes the ref count to 1 return new obj(); } I also checked, just in case, behaviour of calling this (a bit nonsensical) code: shared class Plane: Std::TangibleObject { Plane() { CollisionShape::makePlane(vec3(0, 1, 0), 0.0f); } void cleanUp() override { TangibleObject::cleanUp(); @rigidBody = null; @collisionShape = null; @mesh = null; } CollisionShape@ collisionShape; RigidBody@ rigidBody; StaticMesh@ mesh; } and it seems to result in just single FREE, taking refCount from 1(initial, from ctor) -> 0 and removing the created object asap. This works without crashes - just not sure why it FREEs without adding ref, so it must expect the outside the be adding ref probably? It's not that clear to me how AS calls addRef/release during various situations - I will try to make some diagram once I get the hang of it, but the case with factory function is a weird one.
  12. UPDATE: SOLVED BY RUBBER-DUCKING Thanks for looking at it! The problem is, I can't see any obvious trace of it, nor I recall writing any. Searching through the code also does not show anything, especially when compared to other classes behaviour which is fine. Also - wouldn't it not show like this on the callstack where it looks like 2 refadds are initiated from within script engine, not from the outside? There should be refadd & refdel when AS is dealing with the returned object, but where does that second refadd comes from? It's also initiated within scripting. This is debugger just before the created instance is handed over to AngelScript: Here is how makeBox looks: CollisionShapeScriptProxy* CollisionShapeFactory::makeBox(const glm::vec3& halfExtents) { auto handle = store_.emplace(CollisionShape::Type::Box, std::make_unique<btBoxShape>(btVector3(halfExtents.x, halfExtents.y, halfExtents.z))); return makeCollisionShapeScriptProxy(handle); } That's makeBox - it creates an instance (store_.emplace) but this has nothing to do with scripting, it's C++ only and not refcounted. Then it passes the created instance to proxy, which does this: CollisionShapeScriptProxy* CollisionShapeFactory::makeCollisionShapeScriptProxy(CollisionShapes::Handle& handle) { return new CollisionShapeScriptProxy(store_, handle, 1); } Last parameter is initial refCount passed - I was trying to work around the problem, knowing there is one refcount too many coming from the scripting, and for this class only I tried to pass 0 (->release() would not work because it would cause object to be prematurely destroyed) but it didn't solve the issue and crashed. So that's all I have on non-Angelscript side, this call above is what is registered as asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeBox(const vec3 &in)", asMETHOD(CollisionShapeFactory, makeBox), asCALL_THISCALL_ASGLOBAL, this)); later. When CollisionShapeScriptProxy is created above, its refcount is 1 and then something happens inside the script that changes it - the code for script itself I already pasted. Just for the sake of completion this is part of the base ScriptProxy class that implements refCounting for all the classes (the ones that work and CollisionShape): ScriptProxy(SlotMap<T>& container, const typename SlotMap<T>::Handle& handle) : ScriptProxy(container, handle, 1) { } ScriptProxy(SlotMap<T>& container, const typename SlotMap<T>::Handle& handle, int16_t initialRefcount) : containerRef_(container), handle_(handle), refCount_(initialRefcount) { } void addRef() { VLOG(3) << typeid(T).name() << "[" << this << "]++ (" << refCount_ << ") -> \n" << getCallStack(2,6); refCount_++; } void release() { VLOG(3) << typeid(T).name() << "[" << this << "]-- (" << refCount_ << ") -> \n" << getCallStack(2,6); CHECK(handle_ != SlotMap<T>::NullHandle); if (--refCount_ == 0) delete this; }
  13. I managed to solve most of my problems, but encountered a new one - and since it's related to refcounting script registered OBJ_REF classes, I thought I will continue here rather than start a new topic. I've spent some hours debugging this and I have literally no idea why this happens, so hope @WitchLord or anyone knowing AS internals much better than me will be able to help. asCHECK(engine->RegisterObjectType("CollisionShape", 0, asOBJ_REF)); asCHECK(engine->RegisterObjectBehaviour("CollisionShape", asBEHAVE_ADDREF, "void f()", asMETHOD(CollisionShapeScriptProxy, addRef), asCALL_THISCALL)); asCHECK(engine->RegisterObjectBehaviour("CollisionShape", asBEHAVE_RELEASE, "void f()", asMETHOD(CollisionShapeScriptProxy, release), asCALL_THISCALL)); asCHECK(engine->SetDefaultNamespace("CollisionShape")); asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeSphere(float)", asMETHOD(CollisionShapeFactory, makeSphere), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makePlane(const vec3 &in, float)", asMETHOD(CollisionShapeFactory, makePlane), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterGlobalFunction("CollisionShape@ makeBox(const vec3 &in)", asMETHOD(CollisionShapeFactory, makeBox), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->SetDefaultNamespace("")); Important note on what's different here than my other classes (which work fine!): this class has no factory registered, because I want to have several factory functions which are registered as globals to make different kinds of the same CollisionShape. Now, the class has the same mechanism of refcounting as my other component-classes (transform, animator, skeleton etc.) but only this class has weird behaviour of AddRef happening one time too many. Lifetime of this class is as follow: 1. Inside Script Object it's created via @collisionShape = CollisionShape::makeBox(...); 2. Default ref count is 1, class is created with new CollisionShapeProxy, then it's destroyed when refcount reaches 0. 3. CollisionShape is passed to RigidBody which AddRefs it during its lifetime then Releases, but the problem does not lie there, and to rule it out I stopped affecting refcount when it's passed to RigidBody for now. So all that keeps hold on that object is @collisionShape assignment shown above. 4. When I destroy the object, it cleans up doing this: @collisionShape = null; So this should effectively delete the proxy because neither RigidBody nor ScriptObject holds reference anymore... but it doesn't. All other objects behave like this but this one stays on 1 refcount for some unknown reason. I started dumping all addrefs & releases including few lines of callstack and this is what happens during its lifetime: 1 2018-10-21 21:08:59,136891 slot_map.h:88 [VERBOSE] [class CollisionShape] Creating new element @ sparseIndex 0, version: 0 2 2018-10-21 21:09:02,875345 slotmap_script_proxy.h:61 [VERBOSE] class CollisionShape[1370FB38]++ (1) -> 3 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 4 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 5 asCContext::ExecuteNext [as_context.cpp:2893] 6 asCContext::Execute [as_context.cpp:1328] 7 2018-10-21 21:09:02,875345 slotmap_script_proxy.h:67 [VERBOSE] class CollisionShape[1370FB38]-- (2) -> 8 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 9 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 10 asCContext::ExecuteNext [as_context.cpp:2815] 11 asCContext::Execute [as_context.cpp:1328] 12 2018-10-21 21:09:06,515185 slotmap_script_proxy.h:61 [VERBOSE] class CollisionShape[1370FB38]++ (1) -> 13 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 14 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 15 asCContext::ExecuteNext [as_context.cpp:4152] 16 asCContext::Execute [as_context.cpp:1328] --- here script object is destroyed, all resources released (except CollisionShape which stays alive --- 17 2018-10-21 21:09:08,394326 slotmap_script_proxy.h:67 [VERBOSE] class CollisionShape[1370FB38]-- (2) -> 18 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4069] 19 asCScriptEngine::CallObjectMethod [as_scriptengine.cpp:4013] 20 asCContext::ExecuteNext [as_context.cpp:2888] 21 asCContext::Execute [as_context.cpp:1328] Numbers in ( ) are refCount BEFORE it's decreased or increased. So we begin with line 2, refcount (1) which is initial refcount and it's increased (2). Then it's decreased on line 7, so we're back to (1), but then again it's increased to (2) on line 12 and it stays like this. So the only thing that's referencing our CollisionShape is the script, and somehow it holds 2 references. Then at line 17 we have decref due to destruction, so it goes down to (1) and stays like this forever - it will never be cleaned up. Nothing like this happens with other classes using same base refcounted class... The only difference I see is that this class is the only one made not through factory behaviour but global function, but it has the same declaration as factory. I took screenshots of these 3 calls, inside context where it seems to be most relevant - 2 addrefs & 1 release: \ I have no idea what happens here - seems like there are two things that increase ref: asBC_REFCPY, then asBC_RefCpyV, but only one that decreases asBC_FREE. This leaves the proxy refcount at 2 (initial 1 + non-released ref during script execution). The whole thing happens during construction of script object that holds the reference, and CollisionShape@ is created inside its constructor like this: So... if anyone has any idea what's going on with this additional addRef - please halp! Sorry for that long post, but I lack the insight to follow what's going on there regarding lifetime and refcounting - I just don't know when AS increases those and when not etc. I hope that by providing that much information someone will spot the problem..
  14. noizex

    Problem with value type & opAssign

    Thanks! To be honest I'm not sure why I didn't make it asOBJ_POD - I'm pretty sure that would be the first thing to try for me.. I tried changing it and it now compiles and seems to work fine.
  15. Hi, I try to wrap my head around operator behaviour, documentation does not say much for the C++ side, so I guess it should be probably simple but I can't get this to work: # this works vec3 a(1.0f); vec3 b(0.0f); vec3 c = a - b; # this doesn't Transform@ transform = Transform(); vec3 a(1.0f); vec3 c = a - transform.position; (70): No appropriate opAssign method found in 'vec3' for value assignment (70): Previous error occurred while attempting to create a temporary copy of object Transform register: asCHECK(engine->RegisterObjectType("Transform", 0, asOBJ_REF)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_FACTORY, "Transform@ f()", asMETHOD(SpatialWorld, makeTransform), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_ADDREF, "void f()", asMETHOD(TransformScriptProxy, addRef), asCALL_THISCALL)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_RELEASE, "void f()", asMETHOD(TransformScriptProxy, release), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "vec3 get_forward() const", asMETHOD(TransformScriptProxy, getForward), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "vec3 get_position() const", asMETHOD(TransformScriptProxy, getPosition), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "void set_position(const vec3 &in)", asMETHOD(TransformScriptProxy, setPosition), asCALL_THISCALL)); vec3 register: // Type & behaviours asCHECK(m_engine->RegisterObjectType("vec3", sizeof(glm::vec3), asOBJ_VALUE | asGetTypeTraits<glm::vec3>())); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(vec3_ConstructorEmpty), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f(float, float, float)", asFUNCTION(vec3_Constructor), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(vec3_ConstructorScalar), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(vec3_Destructor), asCALL_CDECL_OBJFIRST)); // Properties asCHECK(m_engine->RegisterObjectProperty("vec3", "float x", asOFFSET(glm::vec3, x))); asCHECK(m_engine->RegisterObjectProperty("vec3", "float y", asOFFSET(glm::vec3, y))); asCHECK(m_engine->RegisterObjectProperty("vec3", "float z", asOFFSET(glm::vec3, z))); // Operators asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opAddAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator+=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opMulAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator*=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opAdd(const vec3 &in) const", asFUNCTIONPR(glm::operator+, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opSub(const vec3 &in) const", asFUNCTIONPR(glm::operator-, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opMul(const vec3 &in) const", asFUNCTIONPR(glm::operator*, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opMul_r(float) const", asFUNCTIONPR(glm::operator*, (float, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opDiv(const vec3 &in) const", asFUNCTIONPR(glm::operator/, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); // Methods asCHECK(m_engine->RegisterObjectMethod("vec3", "float length() const", asFUNCTIONPR(glm::length, (const glm::vec3&), float), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "float dot(const vec3& in) const", asFUNCTIONPR(glm::dot, (const glm::vec3&, const glm::vec3&), float), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 normalize() const", asFUNCTIONPR(glm::normalize, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "string str()", asFUNCTIONPR(glm::to_string, (const glm::vec3&), std::string), asCALL_CDECL_OBJLAST)); Anyone knows what might be wrong here? Also if you spot some obvious inefficiencies please let me know - vec3 is small class (it's glm::vec3) that can be copied and used by value - maybe the problem is that I return a value from Transform::get_position() instead of reference? Or that I registered vec3::opAssign as returning reference, but without it I was having errors with registers and overall breakage...
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!