1 //
2 //   Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net>
3 //
4 //   This program is free software; you can redistribute it and/or modify
5 //   it under the terms of the GNU General Public License version 2 as
6 //   published by the Free Software Foundation.
7 //
8 //   This program is distributed in the hope that it will be useful,
9 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //   GNU General Public License version 2 for more details.
12 //
13 //   You should have received a copy of the GNU General Public License
14 //   version 2 along with this program; if not, write to the
15 //   Free Software Foundation, Inc.,
16 //   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 //
18 
19 #ifndef SPRITE_MAPPER_H
20 #define SPRITE_MAPPER_H
21 
22 #include "ly_counter.h"
23 #include "../savestate.h"
24 
25 namespace gambatte {
26 
27 class NextM0Time;
28 
29 class SpriteMapper {
30 public:
31 	SpriteMapper(NextM0Time &nextM0Time,
32 	             LyCounter const &lyCounter,
33 	             unsigned char const *oamram);
34 	void reset(unsigned char const *oamram, bool cgb);
35 	unsigned long doEvent(unsigned long time);
largeSprites(unsigned spNo)36 	bool largeSprites(unsigned spNo) const { return oamReader_.largeSprites(spNo); }
numSprites(unsigned ly)37 	unsigned numSprites(unsigned ly) const { return num_[ly] & ~need_sorting_mask; }
oamChange(unsigned long cc)38 	void oamChange(unsigned long cc) { oamReader_.change(cc); }
oamChange(unsigned char const * oamram,unsigned long cc)39 	void oamChange(unsigned char const *oamram, unsigned long cc) { oamReader_.change(oamram, cc); }
oamram()40 	unsigned char const * oamram() const { return oamReader_.oam(); }
posbuf()41 	unsigned char const * posbuf() const { return oamReader_.spritePosBuf(); }
preSpeedChange(unsigned long cc)42 	void  preSpeedChange(unsigned long cc) { oamReader_.update(cc); }
postSpeedChange(unsigned long cc)43 	void postSpeedChange(unsigned long cc) { oamReader_.change(cc); }
44 
resetCycleCounter(unsigned long oldCc,unsigned long newCc)45 	void resetCycleCounter(unsigned long oldCc, unsigned long newCc) {
46 		oamReader_.update(oldCc);
47 		oamReader_.resetCycleCounter(oldCc, newCc);
48 	}
49 
setLargeSpritesSource(bool src)50 	void setLargeSpritesSource(bool src) { oamReader_.setLargeSpritesSrc(src); }
51 
sprites(unsigned ly)52 	unsigned char const * sprites(unsigned ly) const {
53 		if (num_[ly] & need_sorting_mask)
54 			sortLine(ly);
55 
56 		return spritemap_ + ly * 10;
57 	}
58 
setStatePtrs(SaveState & state)59 	void setStatePtrs(SaveState &state) { oamReader_.setStatePtrs(state); }
enableDisplay(unsigned long cc)60 	void enableDisplay(unsigned long cc) { oamReader_.enableDisplay(cc); }
saveState(SaveState & state)61 	void saveState(SaveState &state) const { oamReader_.saveState(state); }
62 
loadState(SaveState const & state,unsigned char const * oamram)63 	void loadState(SaveState const &state, unsigned char const *oamram) {
64 		oamReader_.loadState(state, oamram);
65 		mapSprites();
66 	}
67 
inactivePeriodAfterDisplayEnable(unsigned long cc)68 	bool inactivePeriodAfterDisplayEnable(unsigned long cc) const {
69 		return oamReader_.inactivePeriodAfterDisplayEnable(cc);
70 	}
71 
schedule(LyCounter const & lyCounter,unsigned long cc)72 	static unsigned long schedule(LyCounter const &lyCounter, unsigned long cc) {
73 		return lyCounter.nextLineCycle(80, cc);
74 	}
75 
76 private:
77 	class OamReader {
78 	public:
79 		OamReader(LyCounter const &lyCounter, unsigned char const *oamram);
80 		void reset(unsigned char const *oamram, bool cgb);
81 		void change(unsigned long cc);
change(unsigned char const * oamram,unsigned long cc)82 		void change(unsigned char const *oamram, unsigned long cc) { change(cc); oamram_ = oamram; }
changed()83 		bool changed() const { return lastChange_ != 0xFF; }
largeSprites(unsigned spNo)84 		bool largeSprites(unsigned spNo) const { return szbuf_[spNo]; }
oam()85 		unsigned char const * oam() const { return oamram_; }
resetCycleCounter(unsigned long oldCc,unsigned long newCc)86 		void resetCycleCounter(unsigned long oldCc, unsigned long newCc) { lu_ -= oldCc - newCc; }
setLargeSpritesSrc(bool src)87 		void setLargeSpritesSrc(bool src) { largeSpritesSrc_ = src; }
88 		void update(unsigned long cc);
spritePosBuf()89 		unsigned char const * spritePosBuf() const { return buf_; }
90 		void setStatePtrs(SaveState &state);
91 		void enableDisplay(unsigned long cc);
saveState(SaveState & state)92 		void saveState(SaveState &state) const { state.ppu.enableDisplayM0Time = lu_; }
93 		void loadState(SaveState const &ss, unsigned char const *oamram);
inactivePeriodAfterDisplayEnable(unsigned long cc)94 		bool inactivePeriodAfterDisplayEnable(unsigned long cc) const { return cc < lu_; }
lineTime()95 		unsigned lineTime() const { return lyCounter_.lineTime(); }
96 
97 	private:
98 		unsigned char buf_[80];
99 		bool szbuf_[40];
100 		LyCounter const &lyCounter_;
101 		unsigned char const *oamram_;
102 		unsigned long lu_;
103 		unsigned char lastChange_;
104 		bool largeSpritesSrc_;
105 		bool cgb_;
106 	};
107 
108 	enum { need_sorting_mask = 0x80 };
109 
110 	mutable unsigned char spritemap_[144 * 10];
111 	mutable unsigned char num_[144];
112 	NextM0Time &nextM0Time_;
113 	OamReader oamReader_;
114 
115 	void clearMap();
116 	void mapSprites();
117 	void sortLine(unsigned ly) const;
118 };
119 
120 }
121 
122 #endif
123