/*
* 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.renderer.android;
import master.flame.danmaku.danmaku.model.BaseDanmaku;
import master.flame.danmaku.danmaku.model.IDanmakuIterator;
import master.flame.danmaku.danmaku.model.IDisplayer;
import master.flame.danmaku.danmaku.model.android.Danmakus;
import master.flame.danmaku.danmaku.util.DanmakuUtils;
public class DanmakusRetainer {
private static IDanmakusRetainer rldrInstance = null;
private static IDanmakusRetainer lrdrInstance = null;
private static IDanmakusRetainer ftdrInstance = null;
private static IDanmakusRetainer fbdrInstance = null;
public static void fix(BaseDanmaku danmaku, IDisplayer disp) {
int type = danmaku.getType();
switch (type) {
case BaseDanmaku.TYPE_SCROLL_RL:
if (rldrInstance == null) {
rldrInstance = new RLDanmakusRetainer();
}
rldrInstance.fix(danmaku, disp);
break;
case BaseDanmaku.TYPE_SCROLL_LR:
if (lrdrInstance == null) {
lrdrInstance = new RLDanmakusRetainer();
}
lrdrInstance.fix(danmaku, disp);
break;
case BaseDanmaku.TYPE_FIX_TOP:
if (ftdrInstance == null) {
ftdrInstance = new FTDanmakusRetainer();
}
ftdrInstance.fix(danmaku, disp);
break;
case BaseDanmaku.TYPE_FIX_BOTTOM:
if (fbdrInstance == null) {
fbdrInstance = new FBDanmakusRetainer();
}
fbdrInstance.fix(danmaku, disp);
break;
case BaseDanmaku.TYPE_SPECIAL:
danmaku.layout(disp, 0, 0);
break;
}
}
public static void clear() {
if (rldrInstance != null) {
rldrInstance.clear();
}
if (lrdrInstance != null) {
lrdrInstance.clear();
}
if (ftdrInstance != null) {
ftdrInstance.clear();
}
if (fbdrInstance != null) {
fbdrInstance.clear();
}
}
public static void release(){
clear();
rldrInstance = null;
lrdrInstance = null;
ftdrInstance = null;
fbdrInstance = null;
}
public interface IDanmakusRetainer {
public void fix(BaseDanmaku drawItem, IDisplayer disp);
public void clear();
}
private static class RLDanmakusRetainer implements IDanmakusRetainer {
protected Danmakus mVisibleDanmakus = new Danmakus(Danmakus.ST_BY_YPOS);
protected boolean mCancelFixingFlag = false;
@Override
public void fix(BaseDanmaku drawItem, IDisplayer disp) {
if (drawItem.isOutside())
return;
float topPos = 0;
boolean shown = drawItem.isShown();
if (!shown) {
mCancelFixingFlag = false;
// 确定弹幕位置
IDanmakuIterator it = mVisibleDanmakus.iterator();
BaseDanmaku insertItem = null, firstItem = null, lastItem = null, minRightRow = null;
boolean overwriteInsert = false;
while (!mCancelFixingFlag && it.hasNext()) {
BaseDanmaku item = it.next();
if(item == drawItem){
insertItem = item;
lastItem = null;
shown = true;
break;
}
if (firstItem == null)
firstItem = item;
if (drawItem.paintHeight + item.getTop() > disp.getHeight()) {
overwriteInsert = true;
break;
}
if (minRightRow == null) {
minRightRow = item;
} else {
if (minRightRow.getRight() >= item.getRight()) {
minRightRow = item;
}
}
// 检查碰撞
boolean willHit = DanmakuUtils.willHitInDuration(disp, item, drawItem,
drawItem.getDuration(), drawItem.getTimer().currMillisecond);
if (!willHit) {
insertItem = item;
break;
}
lastItem = item;
}
if (insertItem != null) {
if (lastItem != null)
topPos = lastItem.getBottom();
else
topPos = insertItem.getTop();
if (insertItem != drawItem){
mVisibleDanmakus.removeItem(insertItem);
shown = false;
}
} else if (overwriteInsert) {
if (minRightRow != null) {
topPos = minRightRow.getTop();
if(minRightRow.paintWidth<drawItem.paintWidth){
mVisibleDanmakus.removeItem(minRightRow);
shown = false;
}
}
} else if (lastItem != null) {
topPos = lastItem.getBottom();
} else if (firstItem != null) {
topPos = firstItem.getTop();
mVisibleDanmakus.removeItem(firstItem);
shown = false;
} else {
topPos = 0;
}
topPos = checkVerticalEdge(overwriteInsert, drawItem, disp, topPos, firstItem,
lastItem);
if (topPos == 0 && mVisibleDanmakus.size()==0) {
shown = false;
}
}
drawItem.layout(disp, drawItem.getLeft(), topPos);
if (!shown) {
mVisibleDanmakus.addItem(drawItem);
}
}
protected float checkVerticalEdge(boolean overwriteInsert, BaseDanmaku drawItem,
IDisplayer disp, float topPos, BaseDanmaku firstItem, BaseDanmaku lastItem) {
if (topPos < 0 || (firstItem!=null && firstItem.getTop() > 0) || topPos + drawItem.paintHeight > disp.getHeight()) {
topPos = 0;
clear();
}
return topPos;
}
@Override
public void clear() {
mCancelFixingFlag = true;
mVisibleDanmakus.clear();
}
}
private static class FTDanmakusRetainer extends RLDanmakusRetainer {
@Override
protected float checkVerticalEdge(boolean overwriteInsert, BaseDanmaku drawItem,
IDisplayer disp, float topPos, BaseDanmaku firstItem, BaseDanmaku lastItem) {
if (topPos + drawItem.paintHeight > disp.getHeight()) {
topPos = 0;
clear();
}
return topPos;
}
}
private static class FBDanmakusRetainer extends FTDanmakusRetainer {
protected Danmakus mVisibleDanmakus = new Danmakus(Danmakus.ST_BY_YPOS_DESC);
@Override
public void fix(BaseDanmaku drawItem, IDisplayer disp) {
if (drawItem.isOutside())
return;
boolean shown = drawItem.isShown();
float topPos = drawItem.getTop();
if (topPos < 0) {
topPos = disp.getHeight() - drawItem.paintHeight;
}
BaseDanmaku removeItem = null, firstItem = null;
if (!shown) {
mCancelFixingFlag = false;
IDanmakuIterator it = mVisibleDanmakus.iterator();
while (!mCancelFixingFlag && it.hasNext()) {
BaseDanmaku item = it.next();
if (item == drawItem) {
removeItem = null;
break;
}
if (firstItem == null) {
firstItem = item;
if (firstItem.getBottom() != disp.getHeight()) {
break;
}
}
if (topPos < 0) {
removeItem = null;
break;
}
// 检查碰撞
boolean willHit = DanmakuUtils.willHitInDuration(disp, item, drawItem,
drawItem.getDuration(), drawItem.getTimer().currMillisecond);
if (!willHit) {
removeItem = item;
// topPos = item.getBottom() - drawItem.paintHeight;
break;
}
topPos = item.getTop() - drawItem.paintHeight;
}
topPos = checkVerticalEdge(false, drawItem, disp, topPos, firstItem, null);
}
drawItem.layout(disp, drawItem.getLeft(), topPos);
if (!shown) {
mVisibleDanmakus.removeItem(removeItem);
mVisibleDanmakus.addItem(drawItem);
}
}
protected float checkVerticalEdge(boolean overwriteInsert, BaseDanmaku drawItem,
IDisplayer disp, float topPos, BaseDanmaku firstItem, BaseDanmaku lastItem) {
if (topPos < 0 || (firstItem != null && firstItem.getBottom() != disp.getHeight())) {
topPos = disp.getHeight() - drawItem.paintHeight;
clear();
}
return topPos;
}
@Override
public void clear() {
mCancelFixingFlag = true;
mVisibleDanmakus.clear();
}
}
}