API Docs for: 0.5.5
Show:

File: kick/scene/CameraPicking.js

define(["kick/math/Vec4", "kick/material/Material", "kick/texture/RenderTexture", "kick/core/Constants", "kick/core/Util", "./PickResult", "kick/core/EngineSingleton"],
    function (Vec4, Material, RenderTexture, Constants, Util, PickResult, EngineSingleton) {
        "use strict";

        /**
         * Camera picking object used by Camera objects to manage picking
         * @private
         * @class CameraPicking
         * @param {Function} setupClearColor
         * @param {Function} renderSceneObjects
         * @param {Scene} sceneObj
         * @param {kick.scene.Camera} camera
         * @constructor
         */
        return function (setupClearColor, renderSceneObjects, sceneObj, camera) {
            if (Constants._ASSERT) {
                if (setupClearColor === EngineSingleton.engine) {
                    Util.fail("CameraPicking constructor changed - engine parameter is removed");
                }
            }
            var engine = EngineSingleton.engine,
                pickingQueue = null,
                pickingMaterial = null,
                pickingRenderTarget = null,
                pickingClearColor = Vec4.create(),
                glState = engine.glState,
                i,
                size = new Float32Array(glState.viewportSize),
                canvasResizedListener = function(newCanvasDimensions){
                    size = new Float32Array(newCanvasDimensions);
                },
                init = function () {
                    pickingQueue = [];
                    pickingMaterial = new Material(
                        {
                            shader: engine.project.load(engine.project.ENGINE_SHADER___PICK),
                            name: "Picking material"
                        }
                    );
                    pickingRenderTarget = new RenderTexture({
                        dimension: size
                    });
                    engine.addEventListener("canvasResized",canvasResizedListener);
                    pickingRenderTarget.name = "__pickRenderTexture";
                };

            init();

            /**
             * @method destroy
             */
            this.destroy = function(){
                engine.removeEventListener("canvasResized",canvasResizedListener);
                if (pickingRenderTarget){
                    pickingRenderTarget.destroy();
                    pickingRenderTarget = null;
                }
            };

            /**
             * Add an object to the picking queue.
             * Picking object must have the signature
             * {gameObjectPickedFn: gameObjectPickedFn,
             * x: x,
             * y: glState.viewportSize[1] - y,
             * width: 1,
             * height: 1,
             * point: true
             * }
             * @method add
             * @param {Object} pickingObject
             */
            this.add = function (pickingObject) {
                pickingQueue.push(pickingObject);
            };

            /**
             * @method handlePickRequests
             * @param {kick.scene.SceneLights} sceneLightObj
             * @param {kick.scene.EngineUniforms} engineUniforms
             */
            this.handlePickRequests = function (sceneLightObj, engineUniforms) {
                if (pickingQueue.length > 0) {
                    if (pickingRenderTarget.dimension[0] !== size[0] ||
                        pickingRenderTarget.dimension[1] !== size[1]){
                        pickingRenderTarget.dimension = size;
                    }
                    glState.currentMaterial = null; // clear current material
                    pickingRenderTarget.bind();
                    setupClearColor(pickingClearColor);
                    engine.gl.clear(Constants.GL_COLOR_BUFFER_BIT | Constants.GL_DEPTH_BUFFER_BIT);
                    engine.gl.pixelStorei(Constants.GL_PACK_ALIGNMENT, 1);
                    renderSceneObjects(sceneLightObj, pickingMaterial);
                    for (i = pickingQueue.length - 1; i >= 0; i--) {
                        // create clojure
                        (function () {
                            var pick = pickingQueue[i],
                                pickArrayLength = pick.width * pick.width * 4,
                                array = new Uint8Array(pickArrayLength),
                                objects = [],
                                objectCount = {},
                                j,
                                subArray,
                                uid,
                                foundObj;
                            engine.gl.readPixels(pick.x, pick.y, pick.width, pick.height, Constants.GL_RGBA, Constants.GL_UNSIGNED_BYTE, array);
                            for (j = 0; j < pickArrayLength; j += 4) {
                                subArray = array.subarray(j, j + 4);
                                uid = Util.vec4uint8ToUint32(subArray);
                                if (uid > 0) {
                                    if (objectCount[uid]) {
                                        objectCount[uid]++;
                                    } else {
                                        foundObj = sceneObj.getObjectByUID(uid);
                                        if (foundObj) {
                                            if (pick.point) {
                                                foundObj = new PickResult(pickingRenderTarget, foundObj, pick.x, pick.y, engineUniforms, camera);
                                            }
                                            objects.push(foundObj);
                                            objectCount[uid] = 1;
                                        }
                                    }
                                }
                            }
                            if (objects.length) {
                                engine.eventQueue.add(function () {
                                    var i,
                                        obj;
                                    for (i = 0; i < objects.length; i++) {
                                        obj = objects[i];
                                        pick.gameObjectPickedFn(obj, objectCount[obj.uid]);
                                    }
                                }, 0);
                            }
                        }());
                    }
                    pickingQueue.length = 0;
                    pickingRenderTarget.unbind();
                }
            };
        };

    });