def main():
    # Parse the command line.
    param = parseCommandLine()

    # Helper class to start/stop Azrael stack and other processes.
    az = azrael.startup.AzraelStack(param.loglevel)

    # Start Azrael services.
    with azutils.Timeit('Startup Time', True):
        az.start()
        if not param.noinit:
            # Add the specified number of cubes in a grid layout.
            demo_default.spawnCubes(*param.cubes, center=(0, 0, -10))

        # Launch a dedicated process to periodically reset the simulation.
        time.sleep(2)
        az.startProcess(demo_default.ResetSim(period=param.reset))

    print('Azrael now live')

    # Start the process that periodically changes the force field. Add the
    # process handle to the list of processes.
    az.startProcess(
        UpdateGrid(period_circ=param.circular, period_lin=param.linear))

    # Either wait forever or start the Qt Viewer and wait for it to return.
    if param.noviewer:
        demolib.waitForever()
    else:
        viewer = demolib.launchQtViewer()
        viewer.wait()

    # Stop Azrael stack.
    az.stop()
    print('Clean shutdown')
Example #2
0
def main():
    # Parse the command line.
    param = parseCommandLine()

    assert vectorgrid.resetGrid('force').ok

    # Helper class to start/stop Azrael stack and other processes.
    az = azrael.startup.AzraelStack(param.loglevel)

    # Start Azrael services.
    with azutils.Timeit('Startup Time', True):
        az.start()
        if not param.noinit:
            # Spawn four cubes in a row.
            spawnCubes(4, 1, 1, center=(0, 0, 10))

        # Launch a dedicated process to periodically reset the simulation.
        time.sleep(2)

    print('Azrael now live')

    # Either wait forever or start the Qt Viewer and wait for it to return.
    if param.noviewer:
        demolib.waitForever()
    else:
        viewer = demolib.launchQtViewer()
        viewer.wait()

    # Stop Azrael stack.
    az.stop()
    print('Clean shutdown')
Example #3
0
def main():
    # Parse the command line.
    param = parseCommandLine()

    # Helper class to start/stop Azrael stack and other processes.
    az = azrael.startup.AzraelStack(param.loglevel)

    # Start Azrael services.
    with azutils.Timeit('Startup Time', True):
        az.start()
        if not param.noinit:
            # Add a model to the otherwise empty simulation. The sphere is
            # in the repo whereas the Vatican model is available here:
            # http://artist-3d.com/free_3d_models/dnm/model_disp.php?\
            # uid=3290&count=count
            # p = os.path.dirname(os.path.abspath(__file__))
            # fname = os.path.join(p, 'models', 'sphere', 'sphere.obj')
            # fname = os.path.join(p, 'house', 'house.obj')
            # fname = os.path.join(p, 'test.obj')
            # scale, model_name = (1.25, fname)
            # scale, model_name = (
            #     50, 'viewer/models/vatican/vatican-cathedral.3ds')
            # scale, model_name = (
            #     1.25, 'viewer/models/house/house.3ds')
            # vert, uv, rgb = demolib.loadModel(model_name)

            # Load the Booster Cube Model created in Blender.
            scale, (vert, uv, rgb) = 1, demolib.loadBoosterCubeBlender()

            # Wrap the UV data into a BoosterCube template and add it to
            # Azrael.
            addBoosterCubeTemplate(scale, vert, uv, rgb)

            # Define additional templates, in this case the wall of cubes.
            # Spawn them a bit to the right and back.
            spawnCubes(*param.cubes, center=(5, 0, -5))
#            del p, fname, model_name

        # Launch a dedicated process to periodically reset the simulation.
        time.sleep(2)
        az.startProcess(ResetSim(period=param.reset))

    print('Azrael now live')

    # Either wait forever or start the Qt Viewer and wait for it to return.
    if param.noviewer:
        demolib.waitForever()
    else:
        viewer = demolib.launchQtViewer()
        viewer.wait()

    # Stop Azrael stack.
    az.stop()
    print('Clean shutdown')
Example #4
0
 def paintGL(self):
     try:
         with util.Timeit('viewer.paintGL') as timeit:
             self._paintGL()
     except Exception as err:
         print('Error in paintGL:')
         print('\n' + '-' * 79)
         print(err)
         import traceback
         traceback.print_exc(file=sys.stdout)
         print('-' * 79 + '\n')
         sys.exit(1)
Example #5
0
    def sendToClerk(self, cmd: str, data: dict):
        """
        Send data to Clerk and return the response.

        This method blocks until a response arrives. Upon a reply it inspects
        the response to determine whether the request succeeded or not. This is
        returned as the first argument in the 'ok' flag.

        .. note::
           JSON must be able to serialise the content of ``data``.

        :param str cmd: command word
        :param dict data: payload (must be JSON encodeable)
        :return: Payload data in whatever form it arrives.
        :rtype: any
        """
        with azutils.Timeit('client.sendToClerk:{}:1'.format(cmd)):
            try:
                payload = json.dumps({'cmd': cmd, 'data': data})
            except (ValueError, TypeError):
                msg = 'JSON encoding error for Client command <{}>'.format(cmd)
                self.logit.warning(msg)
                return RetVal(False, msg, None)

        # Send data and wait for response.
        with azutils.Timeit('client.sendToClerk:{}:2'.format(cmd)):
            self.send(payload)
            payload = self.recv()

        azutils.logMetricQty('client.recv:{}'.format(cmd), len(payload))

        # Decode the response and wrap it into a RetVal tuple.
        with azutils.Timeit('client.sendToClerk:{}:3'.format(cmd)):
            try:
                ret = json.loads(payload)
                ret = RetVal(**ret)
            except (ValueError, TypeError):
                return RetVal(False, 'JSON decoding error in Client', None)

        return ret
Example #6
0
def ToClerk_AddTemplates_Decode(payload: dict):
    """
    Undo the Base64 encoding from all files. Otherwise the templates remain
    unchanged.

    .. raw:: html

       <script src="http://localhost:9000/docson/widget.js"
           data-schema="/json_schemas/template.json">
       </script>

    """

    # Convenience.
    T = aztypes.Template
    dec = base64.b64decode
    with azutils.Timeit('clerk.decode'):
        decoded = []
        # Iterate over all templates.
        for template in payload['templates']:
            # Validate the template against the schema.
            jsonschema.validate(template, azrael.azschemas.Template)

            # Iterate over all fragments in current template.
            for fragname in template['fragments']:
                # Undo the Base64 encoding for each fragment geometry file.
                files = template['fragments'][fragname]['files']
                files = {k: dec(v.encode('utf8')) for k, v in files.items()}

                # Overwrite the original 'file' dictionary.
                template['fragments'][fragname]['files'] = files

            # Turn the input data into a Template type.
            decoded.append(T(**template))

    # Overwrite the original template with the updated version.
    payload['templates'] = decoded
    return payload
def main():
    # Parse the command line.
    param = demo_default.parseCommandLine()

    # Helper class to start/stop Azrael stack and other processes.
    az = azrael.startup.AzraelStack(param.loglevel)

    # Start Azrael services.
    with azutils.Timeit('Startup Time', True):
        az.start()
        if not param.noinit:
            # Define a sphere with boosters and spawn an instance thereof.
            p = os.path.dirname(os.path.abspath(__file__))
            fname = os.path.join(p, 'models', 'sphere', 'sphere.obj')
            spawnSpaceship(scale=1.0, fname=fname)

            # Add the specified number of cubes in a grid layout.
            demo_default.addTexturedCubeTemplates(2, 2, 1)
            del p, fname

        # Launch a dedicated process to periodically reset the simulation.
        time.sleep(2)
        az.startProcess(demo_default.ResetSim(period=param.reset))

    print('Azrael now live')

    # Either wait forever or start the Qt Viewer and wait for it to return.
    if param.noviewer:
        demolib.waitForever()
    else:
        viewer = demolib.launchQtViewer()
        viewer.wait()

    # Stop Azrael stack.
    az.stop()
    print('Clean shutdown')
Example #8
0
    def _paintGL(self):
        """
        Paint the OpenGL scene.

        Qt calls this method whenever it needs re-painting (eg. window
        movement), or when the updateGL() method was called somewhere
        explicitly. In this script we use a timer to periodically trigger the
        updateGL() method for a smooth viewing experience.
        """
        # Update the position/rotation of the camera depending on the
        # currently pressed keys and mouse position.
        self.updateCamera()

        # Load the geometry of newly added objects.
        self.loadGeometry()

        # --------------------------------------------------------------------
        # Draw the scene.
        # --------------------------------------------------------------------
        # Clear the scene.
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        # Compute the combined camera- and projection matrix.
        cameraMat = self.camera.cameraMatrix()
        matPerspCam = np.array(np.dot(self.matPerspective, cameraMat))

        # Convert it to the flat 32Bit format the GPU expects.
        matPerspCam = matPerspCam.astype(np.float32)
        matPerspCam = matPerspCam.flatten(order='F')

        with util.Timeit('viewer.loop') as timeit:
            for objID in self.newSVs:
                # Do not add anything if it is the player object itself.
                if objID == self.player_id:
                    continue

                # Compute the model matrix for the overall object.
                body = self.newSVs[objID]['rbs']
                tmp = {
                    'scale': body['scale'],
                    'position': body['position'],
                    'rotation': body['rotation']
                }
                matModelObj = self.buildModelMatrix(tmp)
                del body, tmp

                # Update each fragment in the scene based on the position,
                # rotation, and scale of the overall object.
                self._drawFragments(objID, matModelObj, matPerspCam)

        # --------------------------------------------------------------------
        # Display HUD for this frame.
        # --------------------------------------------------------------------
        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        gl.glUseProgram(0)
        gl.glColor3f(0.5, 0.5, 0.5)
        hud = 'Frame {}'.format(self.frameCnt)
        if self.recording:
            hud += ', Recording On'
        self.renderText(0, 15, hud)

        # --------------------------------------------------------------------
        # Optional: save the frame buffer content to disk to record a video.
        # --------------------------------------------------------------------
        if self.recording:
            # Time how long it takes to grab the framebuffer.
            t0 = time.time()
            img = self.grabFrameBuffer()
            elapsed = float(1E3 * (time.time() - t0))

            # Send the image to a dedicated writer thread to avoid blocking
            # this thread more than necessary.
            self.imgWriter.sigUpdate.emit(elapsed, img)
            del t0, img, elapsed
        self.frameCnt += 1
Example #9
0
    def loadGeometry(self):
        # Backup the latest state variables because we will download new ones
        # from Azrael shortly.
        self.oldSVs = self.newSVs

        # Get latest SV values.
        with util.Timeit('viewer.getV') as timeit:
            ret = self.client.getObjectStates(None)
            if not ret.ok:
                print('Could not retrieve the state variables -- Abort')
                self.close()

        # Remove all *None* entries (means Azrael does not know about them;
        # should be impossible but just to be sure).
        self.newSVs = {}
        for objID in ret.data:
            if ret.data[objID] is None:
                self._removeObjectData(objID)
            self.newSVs[objID] = ret.data[objID]

        # Remove all objects from the local scene for which Azrael did not
        # provid SV data.
        for objID in self.oldSVs:
            # Ignore the player object.
            if (objID in self.newSVs) or (objID == self.player_id):
                continue

            # Delete all fragment textures.
            for frag in self.textureBuffer[objID].values():
                gl.glDeleteTextures(frag)

            # Delete the corresponding entries in our meta variables.


#            gl.glDeleteBuffers(2, [1, 2])
            self._removeObjectData(objID)

        # The previous loop removed objects that do not exist anymore in
        # Azrael. This loop adds objects that now exist in Azrael but not yet
        # in our scene.
        for objID in list(self.newSVs.keys()):
            # Do not add anything if it is the player object itself.
            if objID == self.player_id:
                continue

            # Skip the object if we already have its model, unless the model
            # changed.
            if (objID in self.oldSVs) and not self.hasGeometryChanged(objID):
                continue

            # Download the latest geometry for this object; skip it if the
            # object does not exist (anymore).
            ret = self.client.getFragments([objID])
            if not ret.ok or ret.data is None or ret.data[objID] is None:
                self._removeObjectData(objID)
                continue

            # Fetch fragment model from Azrael and pass it to the GPU.
            base_url = 'http://{}:{}'.format(self.addr_clerk, self.port_webapi)
            for fragID, frag_data in ret.data[objID].items():
                if frag_data['fragtype'] == 'RAW':
                    url = base_url + frag_data['url_frag'] + '/model.json'
                    frag = requests.get(url).content
                    if len(frag) == 0:
                        self._removeObjectData(objID)
                        break
                    frag = json.loads(frag.decode('utf8'))
                    frag = getFragMetaRaw(frag['vert'], frag['uv'],
                                          frag['rgb'], frag['width'],
                                          frag['height'])
                elif frag_data['fragtype'] == 'DAE':
                    url = base_url + frag_data['url_frag'] + '/' + fragID
                    frag = requests.get(url).content
                    if len(frag) == 0:
                        self._removeObjectData(objID)
                        break
                    with tempfile.TemporaryDirectory() as tmpdir:
                        open('model.dae', 'wb').write(frag)
                        mesh = model_import.loadModelAll('model.dae')

                    # The model may contain several sub-models. Each one has a
                    # set of vertices, UV- and texture maps. The following code
                    # simply flattens the three list-of-lists into three plain
                    # lists.
                    vert = np.array(mesh['vertices']).flatten()
                    uv = np.array(mesh['UV']).flatten()
                    rgb = np.array(mesh['RGB']).flatten()
                    width = height = None

                    # Ensure the data has the correct format.
                    vert = np.array(vert)
                    uv = np.array(uv, np.float32)
                    rgb = np.array(rgb, np.uint8)
                    frag = getFragMetaRaw(vert, uv, rgb, width, height)
                elif frag_data['fragtype'] == '3JS_V3':
                    # Model files in 3JS format. These are stored in a main
                    # JSON file plus (optional) texture files. Find the JSON
                    # file and log an error if there is not exactly one.
                    fnames = [
                        _ for _ in frag_data['files']
                        if _.lower().endswith('.json')
                    ]
                    if len(fnames) != 1:
                        print('{} possible 3JS model candidates'.format(
                            len(fnames)))
                        break

                    # Download the model.
                    url = base_url + frag_data['url_frag'] + '/' + fnames[0]
                    frag = requests.get(url).content
                    if len(frag) == 0:
                        self._removeObjectData(objID)
                        break

                    frag = json.loads(frag.decode('utf8'))
                    vert, uv, rgb = demolib.load3JSModel(frag)

                    # Download a texture file (if the model has one).
                    fnames = [
                        _ for _ in frag_data['files']
                        if _.lower().endswith('.jpg')
                    ]
                    if len(fnames) > 0:
                        print('found texture')
                        url = base_url + frag_data['url_frag'] + '/' + fnames[0]
                        texture = requests.get(url).content
                        assert len(texture) > 0
                        with tempfile.TemporaryDirectory() as tmpdir:
                            open('texture.jpg', 'wb').write(texture)
                            img = PIL.Image.open(fnames[0])
                            width, height = img.size
                            img = np.array(img)
                            rgb = np.rollaxis(np.flipud(img), 1).flatten()
                            print('imported texture {}'.format(url))
                            del img
                        del url, texture
                    del fnames

                    frag = getFragMetaRaw(vert, uv, rgb, width, height)
                else:
                    continue
                self.upload2GPU(objID, fragID, frag)

        # Only draw visible triangles for this fragment.
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glDepthFunc(gl.GL_LESS)