Package com.l2client.model.jme

Source Code of com.l2client.model.jme.VisibleModel

package com.l2client.model.jme;

import java.util.logging.Logger;

import com.jme3.animation.AnimChannel;
import com.jme3.animation.AnimControl;
import com.jme3.bounding.BoundingBox;
import com.jme3.bounding.BoundingSphere;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapFont.Align;
import com.jme3.font.BitmapText;
import com.jme3.font.Rectangle;
import com.jme3.material.Material;
import com.jme3.material.RenderState.BlendMode;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.BillboardControl;
import com.jme3.scene.shape.Quad;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.WrapMode;
import com.l2client.app.Singleton;
import com.l2client.controller.SceneManager;
import com.l2client.controller.SceneManager.Action;
import com.l2client.model.network.NewCharSummary;

/**
* visual representation of a model in 3d space
* has a controller for
* 0) animation
* 1) movement (optionally)
*
* should be subclassed for individual representations of npc's characters, etc.
* A NpcBuilder should construct the individual visual specific detail representations.
*
* Currently all models are based on the same visual model, a modelcache or AssetManager should be used to speed loading of new models (which should be done by a builder/factory patterns anyway)
*
* The loaded 3d model is based on the troll, which is a standin for an unknown/unconfigured 3d model
*/
//TODO animation controller, rigging of actions against animations
public class VisibleModel extends Node {

  public static final String ENTITY_PREFIX = "Entity_";

  Logger logger = Logger.getLogger(VisibleModel.class.getName());

  NewCharSummary charSelection;
 
  /**
   * Node for the text label
   */
  Node label;
 
  static Spatial selection = null;
 
  /**
   * just one health bar visible, the one we have focus on
   */
  static Node healthbar = null;

  /**
   * In the demo all models look alike, so we store a base node
   */
  protected static Node baseNode = null;
  /**
   * The final individual node, including the name of then object above its head
   */
  protected Node vis = null;


  /**
   * Constructor for a vismodel
   *
   * @param sel the NewCharSummary this model should be based on (used for assembling the final visual representation)
   */
  public VisibleModel(NewCharSummary sel) {
    charSelection = sel;
    if(sel != null){
      name = ENTITY_PREFIX+sel.name+"_"+sel.objectId;
    } else {
      name = "Entity_troll_null";
    }
    this.setShadowMode(ShadowMode.Inherit);
  }

  /**
   * Creates the visual if needed by loading it and places the name label above its head
   */
  public void attachVisuals() {
    if (vis != null)
      attachChild(vis);
    else {
      createVisuals();
      if (vis != null)
        attachChild(vis);
    }

    updateLabel();
  }


  public void updateLabel() {
    //The label is created in char space, so if your char is rotated into final position beware that
    //here z is your up vector and not y
    if (vis != null && charSelection != null && charSelection.name != null) {
      if(label != null)
        detachChild(label);

          BitmapFont fnt = Singleton.get().getAssetManager().getJmeAssetMan().loadFont("Interface/Fonts/Default.fnt");
          BitmapText txt = new BitmapText(fnt, false);
          txt.setSize( 0.4f );
          txt.setText(charSelection.name);
          float w = txt.getLineWidth()+20f;
          float off = w*0.5f;
          txt.setBox(new Rectangle(-off, 0f, w, txt.getHeight()));
          txt.setAlignment(Align.Center);
          txt.setQueueBucket(Bucket.Transparent);
          txt.addControl(new BillboardControl());
     
      label = new Node("label");
          if(vis.getWorldBound() instanceof BoundingBox){
            BoundingBox bbox = (BoundingBox)vis.getWorldBound();
            label.setLocalTranslation(0f, bbox.getYExtent()+bbox.getYExtent()+0.5f, 0f);
            logger.finest("Label by BBox "+txt.getText()+" @ "+label.getLocalTranslation());
          }
          else if(vis.getWorldBound() instanceof BoundingSphere){
            BoundingSphere bound = (BoundingSphere)vis.getWorldBound();
            label.setLocalTranslation(0f, bound.getRadius()+bound.getRadius()+0.5f, 0f);
            logger.finest("Label by BSphere "+txt.getText()+" @ "+label.getLocalTranslation());
          }
          else {
            label.setLocalTranslation(0f, 2.5f, 0f);
            logger.finest("Label by Code "+txt.getText()+" @ "+label.getLocalTranslation());
          }
          label.attachChild(txt);
      attachChild(label);
    }
  }
 
  public void addMessageLabel(String msg, ColorRGBA color, float ttl, float speed){
   
        BitmapFont fnt = Singleton.get().getAssetManager().getJmeAssetMan().loadFont("Interface/Fonts/Default.fnt");
        BitmapText txt = new BitmapText(fnt, false);
        txt.setSize( 0.4f );
        txt.setText(msg);
        txt.setColor(color);
        float w = txt.getLineWidth()+20f;
        float off = w*0.5f;
        txt.setBox(new Rectangle(-off, 0f, w, txt.getHeight()));
        txt.setAlignment(Align.Center);
        txt.setQueueBucket(Bucket.Transparent);
        txt.addControl(new MessagesBillboardControl(ttl,speed));
   
        Node node = new Node("Message");
        if(label != null){
          node.setLocalTranslation(0f,label.getLocalTranslation().y+0.5f, 0f);
        } else {
          if(vis.getWorldBound() instanceof BoundingBox){
            BoundingBox bbox = (BoundingBox)vis.getWorldBound();
            node.setLocalTranslation(0f, bbox.getYExtent()+bbox.getYExtent()+0.5f, 0f);
            logger.finest("Message by BBox "+msg+" @ "+node.getLocalTranslation());
          }
          else if(vis.getWorldBound() instanceof BoundingSphere){
            BoundingSphere bound = (BoundingSphere)vis.getWorldBound();
            node.setLocalTranslation(0f, bound.getRadius()+bound.getRadius()+0.5f, 0f);
            logger.finest("Message by BSphere "+msg+" @ "+node.getLocalTranslation());
          }
          else {
            node.setLocalTranslation(0f, 2.5f+0.5f, 0f);
            logger.finest("Message by Code "+msg+" @ "+node.getLocalTranslation());
          }
        }
        node.attachChild(txt);
    Singleton.get().getSceneManager().changeAnyNode(this, node, Action.ADD);
  }
 
  public void addSelectionMarker(ColorRGBA color){
//    if(selection != null){
//      Singleton.get().getSceneManager().changeAnyNode(this, selection, 0);
//    } else {
    if(selection == null)
      selection = createSelectionMarker();
     
      Singleton.get().getSceneManager().changeAnyNode(this, selection, Action.ADD);
      if(vis != null) {
        ColorRGBA cl;
        if(color != null)
        cl = color.clone();
        else
          cl = ColorRGBA.White.clone();
        //use an intensity of 12 for the rimlight
        cl.a = 4f;
        setRimLight(cl, vis);
      }
     
    if(healthbar == null)
      healthbar = createHealthBar();
   
    Singleton.get().getSceneManager().changeAnyNode(this, healthbar, Action.ADD);
//    }
  }
 
  public void removeSelectionMarker(){
    if(selection != null){
      Singleton.get().getSceneManager().changeAnyNode(this, selection, Action.REMOVE);
      if(vis != null)
        setRimLight(ColorRGBA.BlackNoAlpha, vis);
      selection = null;
    }
    if(healthbar != null){
      Singleton.get().getSceneManager().changeAnyNode(this, healthbar, Action.REMOVE);
    }
  }
 
  /**
   * Updates the health bar above a targeted model
   * @param percent  value in 0-1.0 range to scale the health
   */
  public void updateHealthbar(float percent){
    if(healthbar != null){
      healthbar.getChild("health_bar").setLocalScale(percent, 1f, 1f);
    }
  }
 
  private void setRimLight(ColorRGBA color, Node node){
    for(Spatial s : node.getChildren()){
      if(s instanceof Geometry){
        Material m = ((Geometry) s).getMaterial();
        m.setColor("RimLighting", color);//new ColorRGBA(1f, 0f, 0f, 12f));
      }
      if(s instanceof Node) {
        setRimLight(color, (Node) s);
      }
    }
   
  }
 
  private Geometry createSelectionMarker(){
    float size = 2f;
    Geometry selectionMarker = new Geometry("selection", new Quad(size, size));
    selectionMarker.setLocalTranslation(-0.5f*size, 0.2f, 0.5f*size);
    selectionMarker.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));

      com.jme3.asset.AssetManager am = Singleton.get().getAssetManager().getJmeAssetMan();
      Material mat = new Material(am, "Common/MatDefs/Light/Lighting.j3md");
      Texture sel = am.loadTexture("models/textures/flare4.png");
      sel.setWrap(WrapMode.Repeat);
      mat.setTexture("DiffuseMap", sel);
      mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);
      mat.getAdditionalRenderState().setDepthWrite(false);
      selectionMarker.setMaterial(mat);
      selectionMarker.setQueueBucket(Bucket.Transparent);
      selectionMarker.setShadowMode(ShadowMode.Off);
     
      return selectionMarker; 
  }
 
 
  private Node createHealthBar(){
    Node n = new Node("health");
    Geometry frame = new Geometry("health_frame", new Quad(1f, 0.02f));
    Material mat = null;
      com.jme3.asset.AssetManager am = Singleton.get().getAssetManager().getJmeAssetMan();
      mat = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.White);
      frame.setMaterial(mat);
      frame.setQueueBucket(Bucket.Transparent);
      frame.setShadowMode(ShadowMode.Off);
    frame.setLocalTranslation(-0.5f, 0.11f, 0f);
      n.attachChild(frame);
     
    Geometry bar = new Geometry("health_bar", new Quad(1f, 0.1f));
      mat = new Material(am, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Red);
        bar.setMaterial(mat);
      bar.setQueueBucket(Bucket.Transparent);
        bar.setShadowMode(ShadowMode.Off);
        bar.setLocalTranslation(-0.5f, 0f, 0f);
      n.attachChild(bar);
        if(vis.getWorldBound() instanceof BoundingBox){
          BoundingBox bbox = (BoundingBox)vis.getWorldBound();
          n.setLocalTranslation(0f, bbox.getYExtent()+0.6f, 0f);
          logger.finest("Healthbar by BBox @ "+n.getLocalTranslation());
        }
        else if(vis.getWorldBound() instanceof BoundingSphere){
          BoundingSphere bound = (BoundingSphere)vis.getWorldBound();
          n.setLocalTranslation(0f, bound.getRadius()+0.6f, 0f);
          logger.finest("Healthbar by BSphere @ "+n.getLocalTranslation());
        }
        else {
          n.setLocalTranslation(0f, 2.8f, 0f);
          logger.finest("Healthbar by Code @ "+n.getLocalTranslation());
        }
        n.addControl(new BillboardControl());
//        n.setLocalRotation(new Quaternion().fromAngleAxis(FastMath.HALF_PI, Vector3f.UNIT_X));
//        n.updateGeometricState();

      return n; 
  }
 
  /**
   * Builds the visual representation (no text decorator, ec.) of the model by loading it currently.
   * The anim controller seems to be missing from the jme stored version, so currently
   * we load the model from the plain ogre xml definition (which is a bit slower)
   *
   *
   * @return the loaded model on a @see Node
   */
  //FIXME move to a builder, whcih should know what assets to load for which visual (stored in the DB)
  protected Node createVisuals() {

//    if (charSelection != null) {
      if (baseNode == null) { 
//        Asset a = new Asset("troll2/troll.xml.mesh.xml","troll");
//        com.l2client.asset.Singleton.get().getAssetManager().loadAsset(a,true);
        Spatial s = Singleton.get().getAssetManager().getJmeAssetMan().loadModel("models/troll2/troll.xml.mesh.xml");
//        baseNode = (Node) a.getBaseAsset();
        if(s instanceof Node ){
        baseNode = (Node) s;
        baseNode.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
        baseNode.setName(name);
        }
      }
      if (baseNode != null) {
//        //TODO check if still needed
//        //FIXME modelconverter should already have set this one, this is not the case -> NPE
//        baseNode.setModelBound(new BoundingBox());
//        baseNode.updateModelBound();
//        baseNode.updateGeometricState();
        vis = baseNode.clone(false);
        vis.setName(name);
       
        AnimControl animControl = vis.getControl(AnimControl.class);
        AnimChannel chan;
        if(animControl != null) {
         
          if (animControl.getNumChannels()<=0){
            animControl.createChannel();
          }
          chan = animControl.getChannel(0);
            chan.setAnim("idle");
            chan.setTime(animControl.getAnimationLength("idle")
            * FastMath.nextRandomFloat());
         
        } else {
          logger.severe("Vis animations are missing for troll");
        }
      }
//    }

    return vis;
  }
 
//  /**
//   * Adds a movement controller to move the model to the specified x,y coordinates (z is 0 here)
//   * A previous move controller is removed
//   * @param toX target position in world coords x
//   * @param toY target position in world coords y
//   * @param toZ ignored
//   * @param speed   speed per second to be used for traveling
//   */
//  // FIXME ignores height at the moment!
//  // FIXME add and remove should be done via scenemanager
//  public void initMoveTo(float toX, float toY, float toZ, float speed) {
//    if (speed > 0f) {
//      AbstractControl rem = getControl(MoveController.class);
//      if (rem != null)
//        removeControl(rem);
//     
//      addControl(new MoveController(this, new Vector3f(toX, 0, toZ), speed));
//    }
//  }
}
TOP

Related Classes of com.l2client.model.jme.VisibleModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.