Welcome to IOPWiki, Commander.
We are searching for editors to complete gameplay topics in all games. You can contribute without an account. Learn how to contribute and join our Discord server.

MediaWiki:Gadget-artTab.js: Difference between revisions

Welcome to IOP Wiki. This website is maintained by the Girls' Frontline community and is free to edit by anyone.
Jump to navigation Jump to search
Pianoforte (talk | contribs)
m Reverted edits by Pianoforte (talk) to last revision by Messing with data
Added document-ready wait functionality as the MediaWiki does not wait for DOM
 
(14 intermediate revisions by 2 users not shown)
Line 12: Line 12:
function refreshView(artTabDiv) {
function refreshView(artTabDiv) {
   var tdoll = $(artTabDiv).data('tdollId');
   var tdoll = $(artTabDiv).data('tdollId');
   var costume = $(artTabDiv).data('tdollCostume');
   var costume = $(artTabDiv).attr('data-tdoll-costume');
   var variant = $(artTabDiv).attr('data-tdoll-variant'); // why not data though?
   var variant = $(artTabDiv).attr('data-tdoll-variant'); // why not data though?
    
    
Line 26: Line 26:
       var stage = view.data('live2dStage');
       var stage = view.data('live2dStage');
       stage.removeChildren();
       stage.removeChildren();
       loadLive2dGirl($(artTabDiv).find('.artTabContent'), tdoll, costume, variant, function(live2dData) {
        
        view.closest(".artTab").removeClass("loading");
      var anythingFailedHandler = function(x,y,z) {
        stage.addChild(live2dData);
          view.closest(".artTab").removeClass("loading");
       });
          console.log("Failed loading Live2D", x, y, z);
      };
     
      var loadLive2DgirlSuccessHandler = function(live2dData) {
          view.closest(".artTab").removeClass("loading");
          stage.addChild(live2dData);
       };
 
      var loadLive2DsuccessHandler = function() {
          gfUtils.live2dUtils.loadLive2dGirl($(artTabDiv), tdoll, costume, variant, loadLive2DgirlSuccessHandler, anythingFailedHandler);
      };
     
      mw.loader.using('ext.gadget.live2dAnimation').then(loadLive2DsuccessHandler, anythingFailedHandler);
     });
     });
   } else {
   } else {
Line 68: Line 80:
    
    
   return l2d_tdoll_sprite;
   return l2d_tdoll_sprite;
}
function base64ArrayBuffer(arrayBuffer) {
  var base64    = '';
  var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  var bytes        = new Uint8Array(arrayBuffer);
  var byteLength    = bytes.byteLength;
  var byteRemainder = byteLength % 3;
  var mainLength    = byteLength - byteRemainder;
  var a, b, c, d;
  var chunk;
  var i;
  // Main loop deals with bytes in chunks of 3
  for (i = 0; i < mainLength; i = i + 3) {
    // Combine the three bytes into a single integer
    chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
    // Use bitmasks to extract 6-bit segments from the triplet
    a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18;
    b = (chunk & 258048)  >> 12; // 258048  = (2^6 - 1) << 12;
    c = (chunk & 4032)    >>  6; // 4032    = (2^6 - 1) << 6;
    d = chunk & 63              ; // 63      = 2^6 - 1;
    // Convert the raw binary segments to the appropriate ASCII encoding
    base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
  }
  // Deal with the remaining bytes and padding
  if (byteRemainder == 1) {
    chunk = bytes[mainLength];
    a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2;
    // Set the 4 least significant bits to zero
    b = (chunk & 3)  << 4; // 3  = 2^2 - 1;
    base64 += encodings[a] + encodings[b] + '==';
  } else if (byteRemainder == 2) {
    chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
    a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10;
    b = (chunk & 1008)  >>  4; // 1008  = (2^6 - 1) << 4;
    // Set the 2 least significant bits to zero
    c = (chunk & 15)    <<  2; // 15    = 2^4 - 1;
    base64 += encodings[a] + encodings[b] + encodings[c] + '=';
  }
  return base64;
}
function makeBase64Request(url) {
  var xhr = new XMLHttpRequest();
  var prom = new Promise(function (resolve, reject) {
    xhr.open('GET', url, true);
    xhr.responseType = 'arraybuffer';
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(base64ArrayBuffer(xhr.response));
      } else {
        console.log("this.status not ok", this.status, xhr.statusText, url);
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      console.log("xhr.onerror", this.status, xhr.statusText, url);
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
  });
 
  prom.startProcess = function(param) { xhr.send(param); };
 
  return prom;
}
function hideProgress(container) {
  $(container).find('.live2dloadingprogress').hide();
}
function showProgress(container, done, length) {
  var progress = $(container).find('.live2dloadingprogress').first();
 
  if (progress.length == 0) {
    var centeringFix = $('<span></span>');
    var live2dprogress = $('<div></div>').addClass("live2dprogress").append(centeringFix);
    var live2dprogressbar = $('<div></div>').addClass("live2dprogressbar");
    var live2dprogressbarcontainer = $('<div></div>').addClass("live2dprogressbarcontainer").append(live2dprogressbar);
    progress = $('<div></div>').addClass("live2dloadingprogress").append(live2dprogress).append(live2dprogressbarcontainer);
    $(container).append(progress);
  }
 
  progress.show();
 
  var progressAmount = parseFloat(done / length * 100).toFixed(2);
  progress.find('.live2dprogress span').text(progressAmount+"%");
  progress.find('.live2dprogressbar').css('width', progressAmount + "%");
}
function loadLive2dGirl(container, tdoll, costume, variant, callback) {
  var modelId = tdoll;
  if (costume.length > 0) {
    modelId = modelId + "_" + costume;
  }
  if (variant && variant.length > 0) {
    modelId = modelId + "_" + variant;
  }
 
  $.ajax({
  dataType: "json",
  mimeType: "text/plain",
  url: curl(modelId + "_live2d_model.txt"),
  success: function (data) {
            // Init
            var counter = 0;
            var maxItems = 1000;
            var confun = function() {
              showProgress(container, counter, maxItems);
              counter++;
            };
           
            confun();
           
            json = data;
           
            var loadingJobs = new Array();
           
            // Correct paths
            json.model = curl(modelId + "_live2d_model.moc" + ".skel");
            if (json.hasOwnProperty('physics')) { json.physics = curl(modelId + "_live2d_" + json.physics + ".txt"); }
            if (json.hasOwnProperty('pose')) { json.pose = curl(modelId + "_live2d_" + json.pose + ".txt"); }
           
            var idx = 0;
            for (idx=json.motions.idle.length-1; idx >= 0; idx--) {
              var job = makeBase64Request(curl(modelId + "_live2d_" + json.motions.idle[idx].file + ".txt"));
              job.then(function(promiseData) {
                var _datatoPush = "data:text/plain;base64," + promiseData;
                json.motions.idle.push({ "file": _datatoPush });
                confun();
              });
              json.motions.idle.splice(idx, 1);
              loadingJobs.push(job);
            }
           
            for (idx=json.motions.tap_figure.length-1; idx >= 0 ; idx--) {
              var job = makeBase64Request(curl(modelId + "_live2d_" + json.motions.tap_figure[idx].file + ".txt"));
              job.then(function(promiseData) {
                var _datatoPush = "data:text/plain;base64," + promiseData;
                json.motions.tap_figure.push({ "file": _datatoPush });
                confun();
              });
              json.motions.tap_figure.splice(idx, 1);
              loadingJobs.push(job);
            }
           
            for (idx=0; idx < json.textures.length; idx++) {
              var job = makeBase64Request(curl(modelId + "_live2d_" + json.textures[idx]));
              job.then(function(promiseData) {
                var _datatoPush = "data:image/png;base64," + promiseData;
                json.textures.push(_datatoPush);
                confun();
              });
              json.textures.splice(idx, 1);
              loadingJobs.push(job);
            }
           
            // Ajaxing
            maxItems = loadingJobs.length;
            for (idx=0; idx < loadingJobs.length; idx++) { loadingJobs[idx].startProcess(null); }
           
            // Do it
            var successHandler = function(values) {
                var l2d_tdoll_sprite = createLive2dSprite(json);
                callback(l2d_tdoll_sprite);
                hideProgress(container);
            };
            var failureHandler = function(reason) {
              console.log("Failed ajax", reason);
              hideProgress(container);
            };
            Promise.all(loadingJobs)
                  .then(successHandler)['catch'](failureHandler); // I can't call catch? really?
        }
  });
}
}


Line 328: Line 146:
    
    
   hideLive2dView(artTabDiv);
   hideLive2dView(artTabDiv);
   variantswitcher.find('.right').remove();
   artTabDiv.find('.artTabLive2dSwitch').remove();
    
    
   var basePath = mw.config.get("wgServer") + "/images/";
   var basePath = mw.config.get("wgServer") + "/images/";
Line 336: Line 154:
      
      
   var normArt = artTabDiv.find(".fullart:not(.damaged) a");
   var normArt = artTabDiv.find(".fullart:not(.damaged) a");
   normArt.attr("href", fullartPath );
   normArt.attr("href", "/wiki/File:" + artModelId + ".png");
   normArt.find('img').attr("src", fullartPath );
   normArt.find('img').attr("src", fullartPath );
   normArt.find('img').attr("srcset", fullartPath );
   normArt.find('img').attr("srcset", fullartPath );
Line 342: Line 160:


   var damagedArt = artTabDiv.find(".fullart.damaged a");
   var damagedArt = artTabDiv.find(".fullart.damaged a");
   damagedArt.attr("href", fullartDamagedPath );
   damagedArt.attr("href", "/wiki/File:" + artModelId + "_D.png");
   damagedArt.find('img').attr("src", fullartDamagedPath );
   damagedArt.find('img').attr("src", fullartDamagedPath );
   damagedArt.find('img').attr("srcset", fullartDamagedPath );
   damagedArt.find('img').attr("srcset", fullartDamagedPath );
Line 349: Line 167:
   var isLive2dPossible = doesLive2dAnimationExist(artTabDiv, costumeSuffix);
   var isLive2dPossible = doesLive2dAnimationExist(artTabDiv, costumeSuffix);
   if (isLive2dPossible) {
   if (isLive2dPossible) {
     var live2dButton = $('<button></button>');
     var live2dButtonHandler = function() {
    live2dButton.addClass('artTabLinks');
    live2dButton.addClass('right');
    live2dButton.click(function() {
       if (live2dButton.is('.enabled')) {
       if (live2dButton.is('.enabled')) {
         hideLive2dView($(artTabDiv));
         hideLive2dView($(artTabDiv));
Line 365: Line 180:
         live2dButton.addClass('enabled');
         live2dButton.addClass('enabled');
       }
       }
     });
     };
     live2dButton.text("Live2D");
     var live2dButton = gfUtils.createSliderButton("http://en.gfwiki.com/images/a/a3/live2d-logo.png", live2dButtonHandler);
     variantswitcher.append(live2dButton);
    live2dButton.addClass('artTabLive2dSwitch');
     artTabDiv.append(live2dButton);
   }
   }
    
    
Line 373: Line 189:
}
}


RLQ.push(function () {
RLQ.push(['jquery', function () {
   $(document).ready(function() {  
   $(document).ready(function() {
     var artTabDiv = $('.artTab');
     var artTabDiv = $('.artTab');
     artTabDiv.on('costume_changed', modelChanged);
     artTabDiv.on('costume_changed', modelChanged);
Line 406: Line 222:
     normalButton.click();
     normalButton.click();
   });
   });
});
}]);

Latest revision as of 15:07, 14 October 2019

function switchVariant(artTabDivElement, variant) {
  var artTabDiv = $(artTabDivElement);
  artTabDiv.find('.artTabLinks').removeClass('active');
  artTabDiv.attr('data-tdoll-variant', variant);

  refreshView(artTabDiv);
  
  // Set "active" at the end
  artTabDiv.find(".artTabLinks[data-tdoll-variant='" + variant + "']").addClass('active');
}

function refreshView(artTabDiv) {
  var tdoll = $(artTabDiv).data('tdollId');
  var costume = $(artTabDiv).attr('data-tdoll-costume');
  var variant = $(artTabDiv).attr('data-tdoll-variant'); // why not data though?
  
  $(artTabDiv).find('.artTabContent .fullart').hide();
  
  var live2dActive = $(artTabDiv).find('.live2dstage').is(':visible');
  
  $(artTabDiv).addClass("loading");
  
  if (live2dActive) {
    createLive2dView(artTabDiv, function(view) {
      view.show();
      var stage = view.data('live2dStage');
      stage.removeChildren();
      
      var anythingFailedHandler = function(x,y,z) {
          view.closest(".artTab").removeClass("loading");
          console.log("Failed loading Live2D", x, y, z);
      };
      
      var loadLive2DgirlSuccessHandler = function(live2dData) {
          view.closest(".artTab").removeClass("loading");
          stage.addChild(live2dData);
      };

      var loadLive2DsuccessHandler = function() {
          gfUtils.live2dUtils.loadLive2dGirl($(artTabDiv), tdoll, costume, variant, loadLive2DgirlSuccessHandler, anythingFailedHandler);
      };
      
      mw.loader.using('ext.gadget.live2dAnimation').then(loadLive2DsuccessHandler, anythingFailedHandler);
    });
  } else {
    $(artTabDiv).find(".fullart[data-variant='" + variant + "']").show();
    $(artTabDiv).removeClass("loading");
  }
}

function create_url(base, file) {
  return base + window.gfUtils.createWikiPathPart(file) + file;
}

function curl(file) {
  return create_url("../images/", file);
}

function createLive2dSprite(model) {
  // Live 2D Sprite
  var l2d_tdoll_sprite = new PIXI.Live2DSprite(model, {
    debugLog: false,
    randomMotion: false,
    eyeBlink: true
  });
  l2d_tdoll_sprite.startRandomMotion('idle');
  l2d_tdoll_sprite.on('mousemove', function(evt) {
    const point = evt.data.global;
    l2d_tdoll_sprite.setViewPoint(point.x, point.y);
  });
  l2d_tdoll_sprite.on('click', function(evt) {
    const point = evt.data.global;
    if (l2d_tdoll_sprite.hitTest('body', point.x, point.y)) {
      l2d_tdoll_sprite.startRandomMotionOnce('tap_figure');
      // Info: Maybe add individual hit tests?
    } else {
      l2d_tdoll_sprite.startRandomMotionOnce('tap_figure');
    }
  });
  
  return l2d_tdoll_sprite;
}

function doesLive2dAnimationExist(artTabDiv, costume) {
  var costumeId = costume;
  if (costumeId[0] === '_') {
    costumeId = costumeId.substr(1);
  }
  if (costume == "") {
    costumeId = "costume0";
  }
  
  return $(artTabDiv).attr("data-live2d-exist-" + costumeId) == "true";
}

function hideLive2dView(artTabDiv) {
  var live2dView = $(artTabDiv).find('.live2dstage');
  live2dView.hide();
  var stage = live2dView.data('live2dStage');
  if (stage) {
    stage.removeChildren();
  }

  refreshView(artTabDiv);
}

function createLive2dView(artTabDiv, callback) {
  var live2dView = $(artTabDiv).find('.live2dstage');
  
  if (live2dView.length < 1) {
    mw.loader.using('ext.gadget.live2d').then( function () {
	// Init renderer
	const l2d_tdoll_renderer = PIXI.autoDetectRenderer(550, 550, {transparent: true});
	const l2d_tdoll_stage = new PIXI.Container();

	// Start the animation
	function animate() {
		requestAnimationFrame(animate);
		l2d_tdoll_renderer.render(l2d_tdoll_stage);
	}
	animate();

        var view = $(l2d_tdoll_renderer.view);
        view.data('live2dStage', l2d_tdoll_stage);
        view.addClass('live2dstage');
        view.data('renderer', l2d_tdoll_renderer);

        callback(view);
    });
  } else {
    callback(live2dView.first());
  }
}

function modelChanged(event, costumeSuffix) {
  var artTabDiv = $(event.target).closest('.artTab');
  var tdollId = artTabDiv.data('tdollId');
  var artModelId = tdollId + costumeSuffix;
  var variantswitcher = artTabDiv.find('.variantswitcher');
  
  var costumeId = costumeSuffix;
  if (costumeId[0] === '_') {
    costumeId = costumeId.substr(1);
  }
  artTabDiv.attr('data-tdoll-costume', costumeId);
  
  hideLive2dView(artTabDiv);
  artTabDiv.find('.artTabLive2dSwitch').remove();
  
  var basePath = mw.config.get("wgServer") + "/images/";
  var cpp = window.gfUtils.createWikiPathPart;
  var fullartPath = basePath + "thumb/" + cpp(artModelId +".png") + artModelId +".png/600px-" + artModelId +".png";
  var fullartDamagedPath = basePath + "thumb/" + cpp(artModelId +"_D.png") + artModelId +"_D.png/600px-" + artModelId +"_D.png";
    
  var normArt = artTabDiv.find(".fullart:not(.damaged) a");
  normArt.attr("href", "/wiki/File:" + artModelId + ".png");
  normArt.find('img').attr("src", fullartPath );
  normArt.find('img').attr("srcset", fullartPath );
  normArt.find('img').attr("alt", fullartPath );

  var damagedArt = artTabDiv.find(".fullart.damaged a");
  damagedArt.attr("href", "/wiki/File:" + artModelId + "_D.png");
  damagedArt.find('img').attr("src", fullartDamagedPath );
  damagedArt.find('img').attr("srcset", fullartDamagedPath );
  damagedArt.find('img').attr("alt", fullartDamagedPath );

  var isLive2dPossible = doesLive2dAnimationExist(artTabDiv, costumeSuffix);
  if (isLive2dPossible) {
    var live2dButtonHandler = function() {
      if (live2dButton.is('.enabled')) {
        hideLive2dView($(artTabDiv));
        live2dButton.removeClass('enabled');
      } else {
        $(artTabDiv).addClass("loading");
        createLive2dView(artTabDiv, function(view) {
          view.show();
          $(artTabDiv).find('.artTabContent').first().append(view);
          refreshView(artTabDiv);
        });
        live2dButton.addClass('enabled');
      }
    };
    var live2dButton = gfUtils.createSliderButton("http://en.gfwiki.com/images/a/a3/live2d-logo.png", live2dButtonHandler);
    live2dButton.addClass('artTabLive2dSwitch');
    artTabDiv.append(live2dButton);
  }
  
  refreshView(artTabDiv);
}

RLQ.push(['jquery', function () {
  $(document).ready(function() {
    var artTabDiv = $('.artTab');
    artTabDiv.on('costume_changed', modelChanged);

    var buttonEventHandler = function(event) {
      var currentElement = $(event.target);
      var currentArtTab = currentElement.closest('.artTab');
      var variant = currentElement.data('tdollVariant');
      switchVariant(currentArtTab, variant);
    };
  
    var normalButton = $('<button></button>');
    normalButton.addClass('artTabLinks');
    normalButton.click(buttonEventHandler);
    normalButton.attr('data-tdoll-variant', "");
    normalButton.text("Normal");

    var damagedButton = $('<button></button>');
    damagedButton.addClass('artTabLinks');
    damagedButton.click(buttonEventHandler);
    damagedButton.attr('data-tdoll-variant', "D");
    damagedButton.text("Damaged");
  
    var variantswitcher = $('<div></div>');
    variantswitcher.addClass('variantswitcher');
    variantswitcher.append(normalButton);
    variantswitcher.append(damagedButton);
    
    artTabDiv.prepend(variantswitcher);

    normalButton.click();
  });
}]);