/* * Copyright (C) 2013 Chen Hui <calmer91@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package master.flame.danmaku.danmaku.parser; import android.text.TextUtils; import master.flame.danmaku.danmaku.model.BaseDanmaku; import master.flame.danmaku.danmaku.model.Duration; import master.flame.danmaku.danmaku.model.FBDanmaku; import master.flame.danmaku.danmaku.model.FTDanmaku; import master.flame.danmaku.danmaku.model.IDanmakuIterator; import master.flame.danmaku.danmaku.model.IDanmakus; import master.flame.danmaku.danmaku.model.IDisplayer; import master.flame.danmaku.danmaku.model.L2RDanmaku; import master.flame.danmaku.danmaku.model.R2LDanmaku; import master.flame.danmaku.danmaku.model.SpecialDanmaku; import master.flame.danmaku.danmaku.model.SpecialDanmaku.LinePath; import master.flame.danmaku.danmaku.model.android.DanmakuGlobalConfig; import master.flame.danmaku.danmaku.model.android.Danmakus; public class DanmakuFactory { public final static float OLD_BILI_PLAYER_WIDTH = 539; public final static float BILI_PLAYER_WIDTH = 682; public static int CURRENT_DISP_WIDTH = 0, CURRENT_DISP_HEIGHT = 0; private static float CURRENT_DISP_SIZE_FACTOR = 1.0f; public final static float OLD_BILI_PLAYER_HEIGHT = 385; public final static float BILI_PLAYER_HEIGHT = 438; public final static long COMMON_DANMAKU_DURATION = 3800; // B站原始分辨率下弹幕存活时间 public static final int DANMAKU_MEDIUM_TEXTSIZE = 25; public final static long MIN_DANMAKU_DURATION = 4000; public static long REAL_DANMAKU_DURATION = COMMON_DANMAKU_DURATION; public static long MAX_DANMAKU_DURATION = MIN_DANMAKU_DURATION; public final static long MAX_DANMAKU_DURATION_HIGH_DENSITY = 9000; public static Duration MAX_Duration_Scroll_Danmaku; public static Duration MAX_Duration_Fix_Danmaku; public static Duration MAX_Duration_Special_Danmaku; public static IDanmakus sSpecialDanmakus = new Danmakus(); public static IDisplayer sLastDisp; public static void resetDurationsData() { sLastDisp = null; CURRENT_DISP_WIDTH = CURRENT_DISP_HEIGHT = 0; sSpecialDanmakus.clear(); MAX_Duration_Scroll_Danmaku = null; MAX_Duration_Fix_Danmaku = null; MAX_Duration_Special_Danmaku = null; MAX_DANMAKU_DURATION = MIN_DANMAKU_DURATION; } public static void notifyDispSizeChanged(IDisplayer disp) { if (disp != null) sLastDisp = disp; createDanmaku(BaseDanmaku.TYPE_SCROLL_RL, disp); } public static BaseDanmaku createDanmaku(int type) { return createDanmaku(type, sLastDisp); } public static BaseDanmaku createDanmaku(int type, IDisplayer disp) { if (disp == null) return null; sLastDisp = disp; return createDanmaku(type, disp.getWidth(), disp.getHeight(), CURRENT_DISP_SIZE_FACTOR); } public static BaseDanmaku createDanmaku(int type, IDisplayer disp, float viewportScale) { if (disp == null) return null; sLastDisp = disp; return createDanmaku(type, disp.getWidth(), disp.getHeight(), viewportScale); } /** * 创建弹幕数据请尽量使用此方法,参考BiliDanmakuParser或AcfunDanmakuParser * @param type 弹幕类型 * @param viewportWidth danmakuview宽度,会影响滚动弹幕的存活时间(duration) * @param viewportHeight danmakuview高度 * @param viewportScale 缩放比例,会影响滚动弹幕的存活时间(duration) * @return */ public static BaseDanmaku createDanmaku(int type, int viewportWidth, int viewportHeight, float viewportScale) { return createDanmaku(type, (float) viewportWidth, (float) viewportHeight, viewportScale); } /** * 创建弹幕数据请尽量使用此方法,参考BiliDanmakuParser或AcfunDanmakuParser * @param type 弹幕类型 * @param viewportWidth danmakuview宽度,会影响滚动弹幕的存活时间(duration) * @param viewportHeight danmakuview高度 * @param viewportSizeFactor 会影响滚动弹幕的速度/存活时间(duration) * @return */ public static BaseDanmaku createDanmaku(int type, float viewportWidth, float viewportHeight, float viewportSizeFactor) { boolean sizeChanged = updateViewportState(viewportWidth, viewportHeight, viewportSizeFactor); if (MAX_Duration_Scroll_Danmaku == null) { MAX_Duration_Scroll_Danmaku = new Duration(REAL_DANMAKU_DURATION); MAX_Duration_Scroll_Danmaku.setFactor(DanmakuGlobalConfig.DEFAULT.scrollSpeedFactor); } else if (sizeChanged) { MAX_Duration_Scroll_Danmaku.setValue(REAL_DANMAKU_DURATION); } if (MAX_Duration_Fix_Danmaku == null) { MAX_Duration_Fix_Danmaku = new Duration(COMMON_DANMAKU_DURATION); } if (sizeChanged && viewportWidth > 0) { updateMaxDanmakuDuration(); float scaleX = 1f; float scaleY = 1f; if (CURRENT_DISP_WIDTH > 0 && CURRENT_DISP_HEIGHT > 0) { scaleX = viewportWidth / (float) CURRENT_DISP_WIDTH; scaleY = viewportHeight / (float) CURRENT_DISP_HEIGHT; } if (viewportHeight > 0) { updateSpecialDanmakusDate(scaleX, scaleY); } } BaseDanmaku instance = null; switch (type) { case 1: // 从右往左滚动 instance = new R2LDanmaku(MAX_Duration_Scroll_Danmaku); break; case 4: // 底端固定 instance = new FBDanmaku(MAX_Duration_Fix_Danmaku); break; case 5: // 顶端固定 instance = new FTDanmaku(MAX_Duration_Fix_Danmaku); break; case 6: // 从左往右滚动 instance = new L2RDanmaku(MAX_Duration_Scroll_Danmaku); break; case 7: // 特殊弹幕 instance = new SpecialDanmaku(); sSpecialDanmakus.addItem(instance); break; } return instance; } public static boolean updateViewportState(float viewportWidth, float viewportHeight, float viewportSizeFactor) { boolean sizeChanged = false; if (CURRENT_DISP_WIDTH != (int) viewportWidth || CURRENT_DISP_HEIGHT != (int) viewportHeight || CURRENT_DISP_SIZE_FACTOR != viewportSizeFactor) { sizeChanged = true; REAL_DANMAKU_DURATION = (long) (COMMON_DANMAKU_DURATION * (viewportSizeFactor * viewportWidth / BILI_PLAYER_WIDTH)); REAL_DANMAKU_DURATION = Math.min(MAX_DANMAKU_DURATION_HIGH_DENSITY, REAL_DANMAKU_DURATION); REAL_DANMAKU_DURATION = Math.max(MIN_DANMAKU_DURATION, REAL_DANMAKU_DURATION); CURRENT_DISP_WIDTH = (int) viewportWidth; CURRENT_DISP_HEIGHT = (int) viewportHeight; CURRENT_DISP_SIZE_FACTOR = viewportSizeFactor; } return sizeChanged; } private static void updateSpecialDanmakusDate(float scaleX, float scaleY) { IDanmakus list = sSpecialDanmakus; IDanmakuIterator it = list.iterator(); while (it.hasNext()) { SpecialDanmaku speicalDanmaku = (SpecialDanmaku) it.next(); fillTranslationData(speicalDanmaku, speicalDanmaku.beginX, speicalDanmaku.beginY, speicalDanmaku.endX, speicalDanmaku.endY, speicalDanmaku.translationDuration, speicalDanmaku.translationStartDelay, scaleX, scaleY); LinePath[] linePaths = speicalDanmaku.linePaths; if (linePaths != null && linePaths.length > 0) { int length = linePaths.length; float[][] points = new float[length + 1][2]; for (int j = 0; j < length; j++) { points[j] = linePaths[j].getBeginPoint(); points[j + 1] = linePaths[j].getEndPoint(); } fillLinePathData(speicalDanmaku, points, scaleX, scaleY); } } } public static void updateMaxDanmakuDuration() { long maxScrollDuration = (MAX_Duration_Scroll_Danmaku == null ? 0: MAX_Duration_Scroll_Danmaku.value), maxFixDuration = (MAX_Duration_Fix_Danmaku == null ? 0 : MAX_Duration_Fix_Danmaku.value), maxSpecialDuration = (MAX_Duration_Special_Danmaku == null ? 0: MAX_Duration_Special_Danmaku.value); MAX_DANMAKU_DURATION = Math.max(maxScrollDuration, maxFixDuration); MAX_DANMAKU_DURATION = Math.max(MAX_DANMAKU_DURATION, maxSpecialDuration); MAX_DANMAKU_DURATION = Math.max(COMMON_DANMAKU_DURATION, MAX_DANMAKU_DURATION); MAX_DANMAKU_DURATION = Math.max(REAL_DANMAKU_DURATION, MAX_DANMAKU_DURATION); } public static void updateDurationFactor(float f) { if (MAX_Duration_Scroll_Danmaku == null || MAX_Duration_Fix_Danmaku == null) return; MAX_Duration_Scroll_Danmaku.setFactor(f); updateMaxDanmakuDuration(); } public static void fillText(BaseDanmaku danmaku, String text) { danmaku.text = text; if (TextUtils.isEmpty(text) || !text.contains(BaseDanmaku.DANMAKU_BR_CHAR)) { return; } String[] lines = danmaku.text.split(BaseDanmaku.DANMAKU_BR_CHAR, -1); if (lines.length > 1) { danmaku.lines = lines; } } /** * Initial translation data of the special danmaku * * @param item * @param dispWidth * @param dispHeight * @param beginX * @param beginY * @param endX * @param endY * @param translationDuration * @param translationStartDelay */ public static void fillTranslationData(BaseDanmaku item, float beginX, float beginY, float endX, float endY, long translationDuration, long translationStartDelay, float scaleX, float scaleY) { if (item.getType() != BaseDanmaku.TYPE_SPECIAL) return; ((SpecialDanmaku) item).setTranslationData(beginX * scaleX, beginY * scaleY, endX * scaleX, endY * scaleY, translationDuration, translationStartDelay); updateSpecicalDanmakuDuration(item); } public static void fillLinePathData(BaseDanmaku item, float[][] points, float scaleX, float scaleY) { if (item.getType() != BaseDanmaku.TYPE_SPECIAL || points.length == 0 || points[0].length != 2) return; for (int i = 0; i < points.length; i++) { points[i][0] *= scaleX; points[i][1] *= scaleY; } ((SpecialDanmaku) item).setLinePathData(points); } /** * Initial alpha data of the special danmaku * * @param item * @param beginAlpha * @param endAlpha * @param alphaDuraion */ public static void fillAlphaData(BaseDanmaku item, int beginAlpha, int endAlpha, long alphaDuraion) { if (item.getType() != BaseDanmaku.TYPE_SPECIAL) return; ((SpecialDanmaku) item).setAlphaData(beginAlpha, endAlpha, alphaDuraion); updateSpecicalDanmakuDuration(item); } private static void updateSpecicalDanmakuDuration(BaseDanmaku item) { if (MAX_Duration_Special_Danmaku == null || (item.duration != null && item.duration.value > MAX_Duration_Special_Danmaku.value)) { MAX_Duration_Special_Danmaku = item.duration; updateMaxDanmakuDuration(); } } }