Initial commit
This commit is contained in:
		
						commit
						ff25887f41
					
				
					 119 changed files with 24901 additions and 0 deletions
				
			
		
							
								
								
									
										668
									
								
								src/audio.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										668
									
								
								src/audio.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,668 @@
 | 
			
		|||
/*
 | 
			
		||||
** audio.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "intrulist.h"
 | 
			
		||||
#include "filesystem.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include <SFML/Audio/Music.hpp>
 | 
			
		||||
#include <SFML/Audio/Sound.hpp>
 | 
			
		||||
#include <SFML/Audio/SoundBuffer.hpp>
 | 
			
		||||
#include <SFML/System/Thread.hpp>
 | 
			
		||||
#include <SFML/System/Clock.hpp>
 | 
			
		||||
#include <SFML/System/Sleep.hpp>
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QHash>
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_thread.h"
 | 
			
		||||
 | 
			
		||||
//#include "SDL2/SDL_mixer.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
#define FADE_SLEEP 10
 | 
			
		||||
#define SOUND_MAG_SIZE 10
 | 
			
		||||
#define SOUND_MAX_MEM (50*1000*1000) // 5 MB
 | 
			
		||||
 | 
			
		||||
struct MusicEntity
 | 
			
		||||
{
 | 
			
		||||
	sf::Music music;
 | 
			
		||||
	QByteArray filename;
 | 
			
		||||
	FileStream currentData;
 | 
			
		||||
	SDL_mutex *mutex;
 | 
			
		||||
 | 
			
		||||
	int pitch;
 | 
			
		||||
 | 
			
		||||
	volatile bool fading;
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		unsigned int duration;
 | 
			
		||||
		float msStep;
 | 
			
		||||
		volatile bool terminate;
 | 
			
		||||
		sf::Thread *thread;
 | 
			
		||||
	} fadeData;
 | 
			
		||||
 | 
			
		||||
	/* normalized */
 | 
			
		||||
	float intVolume;
 | 
			
		||||
	float extVolume;
 | 
			
		||||
 | 
			
		||||
	bool extPaused;
 | 
			
		||||
	bool noFadeInFlag;
 | 
			
		||||
 | 
			
		||||
	MusicEntity()
 | 
			
		||||
	    : currentData(0),
 | 
			
		||||
	      pitch(100),
 | 
			
		||||
	      fading(false),
 | 
			
		||||
	      intVolume(1),
 | 
			
		||||
	      extVolume(1),
 | 
			
		||||
	      extPaused(false),
 | 
			
		||||
	      noFadeInFlag(false)
 | 
			
		||||
	{
 | 
			
		||||
		music.setLoop(true);
 | 
			
		||||
		fadeData.thread = 0;
 | 
			
		||||
		mutex = SDL_CreateMutex();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~MusicEntity()
 | 
			
		||||
	{
 | 
			
		||||
		SDL_DestroyMutex(mutex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void play(const QByteArray &filename,
 | 
			
		||||
	          int volume,
 | 
			
		||||
	          int pitch)
 | 
			
		||||
	{
 | 
			
		||||
		terminateFade();
 | 
			
		||||
 | 
			
		||||
		volume = bound<int>(volume, 0, 100);
 | 
			
		||||
		pitch = bound<int>(pitch, 50, 150);
 | 
			
		||||
 | 
			
		||||
		if (filename == this->filename
 | 
			
		||||
		&&  volume == (int)music.getVolume()
 | 
			
		||||
//		&&  pitch == music.getPitch()
 | 
			
		||||
		&&  music.getStatus() == sf::Music::Playing)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (filename == this->filename
 | 
			
		||||
		&&  music.getStatus() == sf::Music::Playing)
 | 
			
		||||
//		&&  pitch == music.getPitch())
 | 
			
		||||
		{
 | 
			
		||||
			intVolume = (float) volume / 100;
 | 
			
		||||
			updateVolumeSync();
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SDL_LockMutex(mutex);
 | 
			
		||||
 | 
			
		||||
		this->music.stop();
 | 
			
		||||
 | 
			
		||||
		this->filename = filename;
 | 
			
		||||
 | 
			
		||||
		currentData.close();
 | 
			
		||||
 | 
			
		||||
		currentData =
 | 
			
		||||
		        gState->fileSystem().openRead(filename.constData(), FileSystem::Audio);
 | 
			
		||||
 | 
			
		||||
		if (!this->music.openFromStream(currentData))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		intVolume = (float) volume / 100;
 | 
			
		||||
		updateVolume();
 | 
			
		||||
//		this->music.setPitch((float) pitch / 100);
 | 
			
		||||
 | 
			
		||||
		if (!extPaused)
 | 
			
		||||
			this->music.play();
 | 
			
		||||
		else
 | 
			
		||||
			noFadeInFlag = true;
 | 
			
		||||
 | 
			
		||||
		SDL_UnlockMutex(mutex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void stop()
 | 
			
		||||
	{
 | 
			
		||||
		terminateFade();
 | 
			
		||||
 | 
			
		||||
		stopPriv();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void fade(unsigned int ms)
 | 
			
		||||
	{
 | 
			
		||||
		if (music.getStatus() != sf::Music::Playing)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (fading)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		delete fadeData.thread;
 | 
			
		||||
		fadeData.thread = new sf::Thread(&MusicEntity::processFade, this);
 | 
			
		||||
		fadeData.duration = ms;
 | 
			
		||||
		fadeData.terminate = false;
 | 
			
		||||
 | 
			
		||||
		fading = true;
 | 
			
		||||
		fadeData.thread->launch();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateVolume()
 | 
			
		||||
	{
 | 
			
		||||
		music.setVolume(intVolume * extVolume * 100);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateVolumeSync()
 | 
			
		||||
	{
 | 
			
		||||
		SDL_LockMutex(mutex);
 | 
			
		||||
		updateVolume();
 | 
			
		||||
		SDL_UnlockMutex(mutex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void terminateFade()
 | 
			
		||||
	{
 | 
			
		||||
		if (!fading)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		/* Tell our thread to wrap up and wait for it */
 | 
			
		||||
		fadeData.terminate = true;
 | 
			
		||||
		fadeData.thread->wait();
 | 
			
		||||
 | 
			
		||||
		fading = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void stopPriv()
 | 
			
		||||
	{
 | 
			
		||||
		SDL_LockMutex(mutex);
 | 
			
		||||
		music.stop();
 | 
			
		||||
		SDL_UnlockMutex(mutex);
 | 
			
		||||
 | 
			
		||||
		filename = QByteArray();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void processFade()
 | 
			
		||||
	{
 | 
			
		||||
		float msStep = music.getVolume() / fadeData.duration;
 | 
			
		||||
		sf::Clock timer;
 | 
			
		||||
		sf::Time sleepTime = sf::milliseconds(FADE_SLEEP);
 | 
			
		||||
		unsigned int currentDur = 0;
 | 
			
		||||
 | 
			
		||||
		while (true)
 | 
			
		||||
		{
 | 
			
		||||
			int elapsed = timer.getElapsedTime().asMilliseconds();
 | 
			
		||||
			timer.restart();
 | 
			
		||||
			currentDur += elapsed;
 | 
			
		||||
 | 
			
		||||
			if (music.getStatus() != sf::Music::Playing)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (fadeData.terminate)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			if (currentDur >= fadeData.duration)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			intVolume = (float) (music.getVolume() - (elapsed * msStep)) / 100;
 | 
			
		||||
			updateVolumeSync();
 | 
			
		||||
 | 
			
		||||
			sf::sleep(sleepTime);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		stopPriv();
 | 
			
		||||
		fading = false;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//struct SoundBuffer
 | 
			
		||||
//{
 | 
			
		||||
//	Mix_Chunk *sdlBuffer;
 | 
			
		||||
//	QByteArray filename;
 | 
			
		||||
//	IntruListLink<SoundBuffer> link;
 | 
			
		||||
 | 
			
		||||
//	SoundBuffer()
 | 
			
		||||
//	    : link(this)
 | 
			
		||||
//	{}
 | 
			
		||||
//};
 | 
			
		||||
 | 
			
		||||
//struct SoundEntity
 | 
			
		||||
//{
 | 
			
		||||
//	IntruList<SoundBuffer> buffers;
 | 
			
		||||
//	QHash<QByteArray, SoundBuffer*> bufferHash;
 | 
			
		||||
//	uint cacheSize; // in chunks, for now
 | 
			
		||||
//	int channelIndex;
 | 
			
		||||
 | 
			
		||||
//	SoundEntity()
 | 
			
		||||
//	    : cacheSize(0),
 | 
			
		||||
//	      channelIndex(0)
 | 
			
		||||
//	{
 | 
			
		||||
//		Mix_AllocateChannels(SOUND_MAG_SIZE);
 | 
			
		||||
//	}
 | 
			
		||||
 | 
			
		||||
//	~SoundEntity()
 | 
			
		||||
//	{
 | 
			
		||||
//		IntruListLink<SoundBuffer> *iter = buffers.iterStart();
 | 
			
		||||
//		iter = iter->next;
 | 
			
		||||
 | 
			
		||||
//		for (int i = 0; i < buffers.getSize(); ++i)
 | 
			
		||||
//		{
 | 
			
		||||
//			SoundBuffer *buffer = iter->data;
 | 
			
		||||
//			iter = iter->next;
 | 
			
		||||
//			delete buffer;
 | 
			
		||||
//		}
 | 
			
		||||
//	}
 | 
			
		||||
 | 
			
		||||
//	void play(const char *filename,
 | 
			
		||||
//	          int volume,
 | 
			
		||||
//	          int pitch)
 | 
			
		||||
//	{
 | 
			
		||||
//		(void) pitch;
 | 
			
		||||
 | 
			
		||||
//		volume = bound(volume, 0, 100);
 | 
			
		||||
 | 
			
		||||
//		Mix_Chunk *buffer = requestBuffer(filename);
 | 
			
		||||
 | 
			
		||||
//		int nextChIdx = channelIndex++;
 | 
			
		||||
//		if (channelIndex > SOUND_MAG_SIZE-1)
 | 
			
		||||
//			channelIndex = 0;
 | 
			
		||||
 | 
			
		||||
//		Mix_HaltChannel(nextChIdx);
 | 
			
		||||
//		Mix_Volume(nextChIdx, ((float) MIX_MAX_VOLUME / 100) * volume);
 | 
			
		||||
//		Mix_PlayChannelTimed(nextChIdx, buffer, 0, -1);
 | 
			
		||||
//	}
 | 
			
		||||
 | 
			
		||||
//	void stop()
 | 
			
		||||
//	{
 | 
			
		||||
//		/* Stop all channels */
 | 
			
		||||
//		Mix_HaltChannel(-1);
 | 
			
		||||
//	}
 | 
			
		||||
 | 
			
		||||
//private:
 | 
			
		||||
//	Mix_Chunk *requestBuffer(const char *filename)
 | 
			
		||||
//	{
 | 
			
		||||
//		SoundBuffer *buffer = bufferHash.value(filename, 0);
 | 
			
		||||
 | 
			
		||||
//		if (buffer)
 | 
			
		||||
//		{
 | 
			
		||||
//			/* Buffer still in cashe.
 | 
			
		||||
//			 * Move to front of priority list */
 | 
			
		||||
//			buffers.remove(buffer->link);
 | 
			
		||||
//			buffers.append(buffer->link);
 | 
			
		||||
 | 
			
		||||
//			return buffer->sdlBuffer;
 | 
			
		||||
//		}
 | 
			
		||||
//		else
 | 
			
		||||
//		{
 | 
			
		||||
//			/* Buffer not in cashe, needs to be loaded */
 | 
			
		||||
//			SDL_RWops ops;
 | 
			
		||||
//			gState->fileSystem().openRead(ops, filename, FileSystem::Audio);
 | 
			
		||||
 | 
			
		||||
//			Mix_Chunk *sdlBuffer = Mix_LoadWAV_RW(&ops, 1);
 | 
			
		||||
 | 
			
		||||
//			if (!sdlBuffer)
 | 
			
		||||
//			{
 | 
			
		||||
//				SDL_RWclose(&ops);
 | 
			
		||||
//				throw Exception(Exception::RGSSError, "Unable to read sound file");
 | 
			
		||||
//			}
 | 
			
		||||
 | 
			
		||||
//			buffer = new SoundBuffer;
 | 
			
		||||
//			buffer->sdlBuffer = sdlBuffer;
 | 
			
		||||
//			buffer->filename = filename;
 | 
			
		||||
 | 
			
		||||
//			++cacheSize;
 | 
			
		||||
 | 
			
		||||
//			bufferHash.insert(filename, buffer);
 | 
			
		||||
//			buffers.prepend(buffer->link);
 | 
			
		||||
 | 
			
		||||
//			if (cacheSize > 20)
 | 
			
		||||
//			{
 | 
			
		||||
//				SoundBuffer *last = buffers.tail();
 | 
			
		||||
//				bufferHash.remove(last->filename);
 | 
			
		||||
//				buffers.remove(last->link);
 | 
			
		||||
//				--cacheSize;
 | 
			
		||||
 | 
			
		||||
//				qDebug() << "Deleted buffer" << last->filename;
 | 
			
		||||
 | 
			
		||||
//				delete last;
 | 
			
		||||
//			}
 | 
			
		||||
 | 
			
		||||
//			return buffer->sdlBuffer;
 | 
			
		||||
//		}
 | 
			
		||||
//	}
 | 
			
		||||
//};
 | 
			
		||||
 | 
			
		||||
struct SoundBuffer
 | 
			
		||||
{
 | 
			
		||||
	sf::SoundBuffer sfBuffer;
 | 
			
		||||
	QByteArray filename;
 | 
			
		||||
	IntruListLink<SoundBuffer> link;
 | 
			
		||||
 | 
			
		||||
	SoundBuffer()
 | 
			
		||||
	    : link(this)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoundEntity
 | 
			
		||||
{
 | 
			
		||||
	IntruList<SoundBuffer> buffers;
 | 
			
		||||
	QHash<QByteArray, SoundBuffer*> bufferHash;
 | 
			
		||||
	unsigned int bufferSamples;
 | 
			
		||||
 | 
			
		||||
	sf::Sound soundMag[SOUND_MAG_SIZE];
 | 
			
		||||
	int magIndex;
 | 
			
		||||
 | 
			
		||||
	SoundEntity()
 | 
			
		||||
	    : bufferSamples(0),
 | 
			
		||||
	      magIndex(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	~SoundEntity()
 | 
			
		||||
	{
 | 
			
		||||
		QHash<QByteArray, SoundBuffer*>::iterator iter;
 | 
			
		||||
		for (iter = bufferHash.begin(); iter != bufferHash.end(); ++iter)
 | 
			
		||||
			delete iter.value();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void play(const char *filename,
 | 
			
		||||
	          int volume,
 | 
			
		||||
	          int pitch)
 | 
			
		||||
	{
 | 
			
		||||
		(void) pitch;
 | 
			
		||||
 | 
			
		||||
		volume = bound<int>(volume, 0, 100);
 | 
			
		||||
 | 
			
		||||
		sf::SoundBuffer &buffer = allocateBuffer(filename);
 | 
			
		||||
 | 
			
		||||
		int soundIndex = magIndex++;
 | 
			
		||||
		if (magIndex > SOUND_MAG_SIZE-1)
 | 
			
		||||
			magIndex = 0;
 | 
			
		||||
 | 
			
		||||
		sf::Sound &sound = soundMag[soundIndex];
 | 
			
		||||
		sound.stop();
 | 
			
		||||
		sound.setBuffer(buffer);
 | 
			
		||||
		sound.setVolume(volume);
 | 
			
		||||
 | 
			
		||||
		sound.play();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void stop()
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < SOUND_MAG_SIZE; i++)
 | 
			
		||||
			soundMag[i].stop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	sf::SoundBuffer &allocateBuffer(const char *filename)
 | 
			
		||||
	{
 | 
			
		||||
		SoundBuffer *buffer = bufferHash.value(filename, 0);
 | 
			
		||||
 | 
			
		||||
		if (buffer)
 | 
			
		||||
		{
 | 
			
		||||
			/* Buffer still in cashe.
 | 
			
		||||
			 * Move to front of priority list */
 | 
			
		||||
 | 
			
		||||
			buffers.remove(buffer->link);
 | 
			
		||||
			buffers.append(buffer->link);
 | 
			
		||||
 | 
			
		||||
			return buffer->sfBuffer;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			/* Buffer not in cashe, needs to be loaded */
 | 
			
		||||
 | 
			
		||||
			FileStream data =
 | 
			
		||||
				gState->fileSystem().openRead(filename, FileSystem::Audio);
 | 
			
		||||
 | 
			
		||||
			buffer = new SoundBuffer;
 | 
			
		||||
			buffer->sfBuffer.loadFromStream(data);
 | 
			
		||||
			bufferSamples += buffer->sfBuffer.getSampleCount();
 | 
			
		||||
 | 
			
		||||
			data.close();
 | 
			
		||||
 | 
			
		||||
//			qDebug() << "SoundCache: Current memory consumption:" << bufferSamples/2;
 | 
			
		||||
 | 
			
		||||
			buffer->filename = filename;
 | 
			
		||||
 | 
			
		||||
			bufferHash.insert(filename, buffer);
 | 
			
		||||
			buffers.prepend(buffer->link);
 | 
			
		||||
 | 
			
		||||
			// FIXME this part would look better if it actually looped until enough memory is freed
 | 
			
		||||
			/* If memory limit is reached, delete lowest priority buffer.
 | 
			
		||||
			 * Samples are 2 bytes big */
 | 
			
		||||
			if ((bufferSamples/2) > SOUND_MAX_MEM && !buffers.isEmpty())
 | 
			
		||||
			{
 | 
			
		||||
				SoundBuffer *last = buffers.tail();
 | 
			
		||||
				bufferHash.remove(last->filename);
 | 
			
		||||
				buffers.remove(last->link);
 | 
			
		||||
				bufferSamples -= last->sfBuffer.getSampleCount();
 | 
			
		||||
 | 
			
		||||
				qDebug() << "Deleted buffer" << last->filename;
 | 
			
		||||
 | 
			
		||||
				delete last;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return buffer->sfBuffer;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AudioPrivate
 | 
			
		||||
{
 | 
			
		||||
	MusicEntity bgm;
 | 
			
		||||
	MusicEntity bgs;
 | 
			
		||||
	MusicEntity me;
 | 
			
		||||
 | 
			
		||||
	SoundEntity se;
 | 
			
		||||
 | 
			
		||||
	sf::Thread *meWatchThread;
 | 
			
		||||
	bool meWatchRunning;
 | 
			
		||||
	bool meWatchThreadTerm;
 | 
			
		||||
 | 
			
		||||
	AudioPrivate()
 | 
			
		||||
	    : meWatchThread(0),
 | 
			
		||||
	      meWatchRunning(false),
 | 
			
		||||
	      meWatchThreadTerm(false)
 | 
			
		||||
	{
 | 
			
		||||
		me.music.setLoop(false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~AudioPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		if (meWatchThread)
 | 
			
		||||
		{
 | 
			
		||||
			meWatchThreadTerm = true;
 | 
			
		||||
			meWatchThread->wait();
 | 
			
		||||
			delete meWatchThread;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bgm.stop();
 | 
			
		||||
		bgs.stop();
 | 
			
		||||
		me.stop();
 | 
			
		||||
		se.stop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void scheduleMeWatch()
 | 
			
		||||
	{
 | 
			
		||||
		if (meWatchRunning)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		meWatchRunning = true;
 | 
			
		||||
 | 
			
		||||
		if (meWatchThread)
 | 
			
		||||
			meWatchThread->wait();
 | 
			
		||||
 | 
			
		||||
		bgm.extPaused = true;
 | 
			
		||||
 | 
			
		||||
		delete meWatchThread;
 | 
			
		||||
		meWatchThread = new sf::Thread(&AudioPrivate::meWatchFunc, this);
 | 
			
		||||
		meWatchThread->launch();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void meWatchFunc()
 | 
			
		||||
	{
 | 
			
		||||
		// FIXME Need to catch the case where an ME is started while
 | 
			
		||||
		// the BGM is still being faded in from this function
 | 
			
		||||
		sf::Time sleepTime = sf::milliseconds(FADE_SLEEP);
 | 
			
		||||
		const int bgmFadeOutSteps = 20;
 | 
			
		||||
		const int bgmFadeInSteps = 100;
 | 
			
		||||
 | 
			
		||||
		/* Fade out BGM */
 | 
			
		||||
		for (int i = bgmFadeOutSteps; i > 0; --i)
 | 
			
		||||
		{
 | 
			
		||||
			if (meWatchThreadTerm)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			if (bgm.music.getStatus() != sf::Music::Playing)
 | 
			
		||||
			{
 | 
			
		||||
				bgm.extVolume = 0;
 | 
			
		||||
				bgm.updateVolumeSync();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bgm.extVolume = (1.0 / bgmFadeOutSteps) * (i-1);
 | 
			
		||||
			bgm.updateVolumeSync();
 | 
			
		||||
			sf::sleep(sleepTime);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SDL_LockMutex(bgm.mutex);
 | 
			
		||||
		if (bgm.music.getStatus() == sf::Music::Playing)
 | 
			
		||||
			bgm.music.pause();
 | 
			
		||||
		SDL_UnlockMutex(bgm.mutex);
 | 
			
		||||
 | 
			
		||||
		/* Linger while ME plays */
 | 
			
		||||
		while (me.music.getStatus() == sf::Music::Playing)
 | 
			
		||||
		{
 | 
			
		||||
			if (meWatchThreadTerm)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			sf::sleep(sleepTime);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SDL_LockMutex(bgm.mutex);
 | 
			
		||||
		bgm.extPaused = false;
 | 
			
		||||
 | 
			
		||||
		if (bgm.music.getStatus() == sf::Music::Paused)
 | 
			
		||||
			bgm.music.play();
 | 
			
		||||
		SDL_UnlockMutex(bgm.mutex);
 | 
			
		||||
 | 
			
		||||
		/* Fade in BGM again */
 | 
			
		||||
		for (int i = 0; i < bgmFadeInSteps; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			if (meWatchThreadTerm)
 | 
			
		||||
				return;
 | 
			
		||||
 | 
			
		||||
			SDL_LockMutex(bgm.mutex);
 | 
			
		||||
 | 
			
		||||
			if (bgm.music.getStatus() != sf::Music::Playing || bgm.noFadeInFlag)
 | 
			
		||||
			{
 | 
			
		||||
				bgm.noFadeInFlag = false;
 | 
			
		||||
				bgm.extVolume = 1;
 | 
			
		||||
				bgm.updateVolume();
 | 
			
		||||
				bgm.music.play();
 | 
			
		||||
				SDL_UnlockMutex(bgm.mutex);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			bgm.extVolume = (1.0 / bgmFadeInSteps) * (i+1);
 | 
			
		||||
			bgm.updateVolume();
 | 
			
		||||
 | 
			
		||||
			SDL_UnlockMutex(bgm.mutex);
 | 
			
		||||
 | 
			
		||||
			sf::sleep(sleepTime);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		meWatchRunning = false;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Audio::Audio()
 | 
			
		||||
	: p(new AudioPrivate)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Audio::bgmPlay(const char *filename,
 | 
			
		||||
					int volume,
 | 
			
		||||
                    int pitch)
 | 
			
		||||
{
 | 
			
		||||
	p->bgm.play(filename, volume, pitch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::bgmStop()
 | 
			
		||||
{
 | 
			
		||||
	p->bgm.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::bgmFade(int time)
 | 
			
		||||
{
 | 
			
		||||
	p->bgm.fade(time);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Audio::bgsPlay(const char *filename,
 | 
			
		||||
					int volume,
 | 
			
		||||
                    int pitch)
 | 
			
		||||
{
 | 
			
		||||
	p->bgs.play(filename, volume, pitch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::bgsStop()
 | 
			
		||||
{
 | 
			
		||||
	p->bgs.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::bgsFade(int time)
 | 
			
		||||
{
 | 
			
		||||
	p->bgs.fade(time);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Audio::mePlay(const char *filename,
 | 
			
		||||
                   int volume,
 | 
			
		||||
                   int pitch)
 | 
			
		||||
{
 | 
			
		||||
	p->me.play(filename, volume, pitch);
 | 
			
		||||
	p->scheduleMeWatch();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::meStop()
 | 
			
		||||
{
 | 
			
		||||
	p->me.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::meFade(int time)
 | 
			
		||||
{
 | 
			
		||||
	p->me.fade(time);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Audio::sePlay(const char *filename,
 | 
			
		||||
                   int volume,
 | 
			
		||||
                   int pitch)
 | 
			
		||||
{
 | 
			
		||||
	p->se.play(filename, volume, pitch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Audio::seStop()
 | 
			
		||||
{
 | 
			
		||||
	p->se.stop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Audio::~Audio() { delete p; }
 | 
			
		||||
							
								
								
									
										52
									
								
								src/audio.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/audio.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
** audio.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef AUDIO_H
 | 
			
		||||
#define AUDIO_H
 | 
			
		||||
 | 
			
		||||
struct AudioPrivate;
 | 
			
		||||
 | 
			
		||||
class Audio
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Audio();
 | 
			
		||||
	~Audio();
 | 
			
		||||
 | 
			
		||||
	void bgmPlay(const char *filename, int volume = 100, int pitch = 100);
 | 
			
		||||
	void bgmStop();
 | 
			
		||||
	void bgmFade(int time);
 | 
			
		||||
 | 
			
		||||
	void bgsPlay(const char *filename, int volume = 100, int pitch = 100);
 | 
			
		||||
	void bgsStop();
 | 
			
		||||
	void bgsFade(int time);
 | 
			
		||||
 | 
			
		||||
	void mePlay(const char *filename, int volume = 100, int pitch = 100);
 | 
			
		||||
	void meStop();
 | 
			
		||||
	void meFade(int time);
 | 
			
		||||
 | 
			
		||||
	void sePlay(const char *filename, int volume = 100, int pitch = 100);
 | 
			
		||||
	void seStop();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	AudioPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // AUDIO_H
 | 
			
		||||
							
								
								
									
										199
									
								
								src/autotiles.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								src/autotiles.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,199 @@
 | 
			
		|||
struct StaticRect { float x, y, w, h; };
 | 
			
		||||
 | 
			
		||||
extern const StaticRect autotileRects[] =
 | 
			
		||||
{
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 64.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 80.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 48.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 32.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 48.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 96.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 80.5, 32.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 64.5, 112.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 0.5, 15, 15 },
 | 
			
		||||
	{ 16.5, 16.5, 15, 15 },
 | 
			
		||||
	{ 0.5, 16.5, 15, 15 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const int autotileRectsN = sizeof(autotileRects) / sizeof(autotileRects[0]);
 | 
			
		||||
							
								
								
									
										43
									
								
								src/binding.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/binding.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,43 @@
 | 
			
		|||
/*
 | 
			
		||||
** binding.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef BINDING_H
 | 
			
		||||
#define BINDING_H
 | 
			
		||||
 | 
			
		||||
struct ScriptBinding
 | 
			
		||||
{
 | 
			
		||||
	/* Starts the part where the binding takes over,
 | 
			
		||||
	 * loading the compressed scripts and executing them.
 | 
			
		||||
	 * This function returns as soon as the scripts finish
 | 
			
		||||
	 * execution or an error is encountered */
 | 
			
		||||
	void (*execute) (void);
 | 
			
		||||
 | 
			
		||||
	/* Instructs the binding
 | 
			
		||||
	 * to immediately terminate script execution. This
 | 
			
		||||
	 * function will perform a longjmp instead of returning,
 | 
			
		||||
	 * so be careful about any variables with local storage */
 | 
			
		||||
	void (*terminate) (void);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* VTable defined in the binding source */
 | 
			
		||||
extern ScriptBinding *scriptBinding;
 | 
			
		||||
 | 
			
		||||
#endif // BINDING_H
 | 
			
		||||
							
								
								
									
										573
									
								
								src/bitmap.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										573
									
								
								src/bitmap.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,573 @@
 | 
			
		|||
/*
 | 
			
		||||
** bitmap.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "bitmap.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL.h"
 | 
			
		||||
#include "SDL2/SDL_image.h"
 | 
			
		||||
#include "SDL2/SDL_ttf.h"
 | 
			
		||||
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
#include "quadarray.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
#include "texpool.h"
 | 
			
		||||
#include "shader.h"
 | 
			
		||||
#include "filesystem.h"
 | 
			
		||||
#include "font.h"
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
 | 
			
		||||
#define DISP_CLASS_NAME "bitmap"
 | 
			
		||||
 | 
			
		||||
struct BitmapPrivate
 | 
			
		||||
{
 | 
			
		||||
	TexFBO tex;
 | 
			
		||||
 | 
			
		||||
	/* 'setPixel()' calls are cached and executed
 | 
			
		||||
	 * in batches on 'flush()' */
 | 
			
		||||
	PointArray pointArray;
 | 
			
		||||
 | 
			
		||||
	Font *font;
 | 
			
		||||
 | 
			
		||||
	BitmapPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		font = &gState->defaultFont();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void bindTextureWithMatrix()
 | 
			
		||||
	{
 | 
			
		||||
		Tex::bind(tex.tex);
 | 
			
		||||
		Tex::bindMatrix(tex.width, tex.height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void bindFBO()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::bind(tex.fbo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void pushSetViewport() const
 | 
			
		||||
	{
 | 
			
		||||
		glState.pushSetViewport(tex.width, tex.height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void popViewport() const
 | 
			
		||||
	{
 | 
			
		||||
		glState.popViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void blitQuad(Quad &quad)
 | 
			
		||||
	{
 | 
			
		||||
		glState.blendMode.pushSet(BlendNone);
 | 
			
		||||
		quad.draw();
 | 
			
		||||
		glState.blendMode.pop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void flushPoints()
 | 
			
		||||
	{
 | 
			
		||||
		if (pointArray.count() == 0)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		Tex::unbind();
 | 
			
		||||
		bindFBO();
 | 
			
		||||
		pushSetViewport();
 | 
			
		||||
		glState.blendMode.pushSet(BlendNone);
 | 
			
		||||
 | 
			
		||||
		pointArray.commit();
 | 
			
		||||
		pointArray.draw();
 | 
			
		||||
		pointArray.reset();
 | 
			
		||||
 | 
			
		||||
		glState.blendMode.pop();
 | 
			
		||||
		popViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void fillRect(const IntRect &rect,
 | 
			
		||||
	              const Vec4 &color)
 | 
			
		||||
	{
 | 
			
		||||
		flushPoints();
 | 
			
		||||
 | 
			
		||||
		bindFBO();
 | 
			
		||||
 | 
			
		||||
		glState.scissorTest.pushSet(true);
 | 
			
		||||
		glState.scissorBox.pushSet(rect);
 | 
			
		||||
		glState.clearColor.pushSet(color);
 | 
			
		||||
 | 
			
		||||
		glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
		glState.clearColor.pop();
 | 
			
		||||
		glState.scissorBox.pop();
 | 
			
		||||
		glState.scissorTest.pop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void ensureFormat(SDL_Surface *&surf, Uint32 format)
 | 
			
		||||
	{
 | 
			
		||||
		if (surf->format->format == format)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		SDL_Surface *surfConv = SDL_ConvertSurfaceFormat(surf, format, 0);
 | 
			
		||||
		SDL_FreeSurface(surf);
 | 
			
		||||
		surf = surfConv;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Bitmap::Bitmap(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	SDL_RWops ops;
 | 
			
		||||
	gState->fileSystem().openRead(ops, filename, FileSystem::Image);
 | 
			
		||||
	SDL_Surface *imgSurf = IMG_Load_RW(&ops, 1);
 | 
			
		||||
 | 
			
		||||
	if (!imgSurf)
 | 
			
		||||
		throw Exception(Exception::SDLError, "SDL: %s", SDL_GetError());
 | 
			
		||||
 | 
			
		||||
	p = new BitmapPrivate;
 | 
			
		||||
 | 
			
		||||
	p->ensureFormat(imgSurf, SDL_PIXELFORMAT_ABGR8888);
 | 
			
		||||
 | 
			
		||||
	p->tex = gState->texPool().request(imgSurf->w, imgSurf->h);
 | 
			
		||||
 | 
			
		||||
	Tex::bind(p->tex.tex);
 | 
			
		||||
	Tex::uploadImage(p->tex.width, p->tex.height, imgSurf->pixels, GL_RGBA);
 | 
			
		||||
 | 
			
		||||
	SDL_FreeSurface(imgSurf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bitmap::Bitmap(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	p = new BitmapPrivate;
 | 
			
		||||
 | 
			
		||||
	p->tex = gState->texPool().request(width, height);
 | 
			
		||||
 | 
			
		||||
	clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bitmap::Bitmap(const Bitmap &other)
 | 
			
		||||
{
 | 
			
		||||
	p = new BitmapPrivate;
 | 
			
		||||
 | 
			
		||||
	p->tex = gState->texPool().request(other.width(), other.height());
 | 
			
		||||
 | 
			
		||||
	other.flush();
 | 
			
		||||
	blt(0, 0, other, rect());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bitmap::~Bitmap()
 | 
			
		||||
{
 | 
			
		||||
	dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Bitmap::width() const
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	return p->tex.width;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Bitmap::height() const
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	return p->tex.height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IntRect Bitmap::rect() const
 | 
			
		||||
{
 | 
			
		||||
	return IntRect(0, 0, width(), height());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::blt(int x, int y,
 | 
			
		||||
                  const Bitmap &source, const IntRect &rect,
 | 
			
		||||
                  int opacity)
 | 
			
		||||
{
 | 
			
		||||
	stretchBlt(IntRect(x, y, rect.w, rect.h),
 | 
			
		||||
	           source, rect, opacity);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::stretchBlt(const IntRect &destRect,
 | 
			
		||||
                         const Bitmap &source, const IntRect &sourceRect,
 | 
			
		||||
                         int opacity)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED;
 | 
			
		||||
 | 
			
		||||
	opacity = bound(opacity, 0, 255);
 | 
			
		||||
 | 
			
		||||
	if (opacity == 0)
 | 
			
		||||
	{
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
//	else if (opacity == 255) /* Fast blit */
 | 
			
		||||
//	{
 | 
			
		||||
//		flush();
 | 
			
		||||
 | 
			
		||||
//		FBO::bind(source.p->tex.fbo, FBO::Read);
 | 
			
		||||
//		FBO::bind(p->tex.fbo, FBO::Draw);
 | 
			
		||||
 | 
			
		||||
//		FBO::blit(sourceRect.x, sourceRect.y, sourceRect.w, sourceRect.h,
 | 
			
		||||
//		          destRect.x,   destRect.y,   destRect.w,   destRect.h);
 | 
			
		||||
//	}
 | 
			
		||||
	else /* Fragment pipeline */
 | 
			
		||||
	{
 | 
			
		||||
		flush();
 | 
			
		||||
 | 
			
		||||
		float normOpacity = (float) opacity / 255.0f;
 | 
			
		||||
 | 
			
		||||
		TexFBO &gpTex = gState->gpTexFBO(destRect.w, destRect.h);
 | 
			
		||||
 | 
			
		||||
		FBO::bind(gpTex.fbo, FBO::Draw);
 | 
			
		||||
		FBO::bind(p->tex.fbo, FBO::Read);
 | 
			
		||||
		FBO::blit(destRect.x, destRect.y, 0, 0, destRect.w, destRect.h);
 | 
			
		||||
 | 
			
		||||
		FloatRect bltSubRect((float) sourceRect.x / source.width(),
 | 
			
		||||
		                     (float) sourceRect.y / source.height(),
 | 
			
		||||
		                     ((float) source.width() / sourceRect.w) * ((float) destRect.w / gpTex.width),
 | 
			
		||||
		                     ((float) source.height() / sourceRect.h) * ((float) destRect.h / gpTex.height));
 | 
			
		||||
 | 
			
		||||
		BltShader &shader = gState->bltShader();
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.setDestination(gpTex.tex);
 | 
			
		||||
		shader.setSubRect(bltSubRect);
 | 
			
		||||
		shader.setOpacity(normOpacity);
 | 
			
		||||
 | 
			
		||||
		Quad quad;
 | 
			
		||||
		quad.setTexPosRect(sourceRect, destRect);
 | 
			
		||||
		quad.setColor(Vec4(1, 1, 1, normOpacity));
 | 
			
		||||
 | 
			
		||||
		source.p->bindTextureWithMatrix();
 | 
			
		||||
		p->bindFBO();
 | 
			
		||||
		p->pushSetViewport();
 | 
			
		||||
 | 
			
		||||
		p->blitQuad(quad);
 | 
			
		||||
 | 
			
		||||
		p->popViewport();
 | 
			
		||||
		shader.unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::fillRect(int x, int y,
 | 
			
		||||
                      int width, int height,
 | 
			
		||||
                      const Vec4 &color)
 | 
			
		||||
{
 | 
			
		||||
	fillRect(IntRect(x, y, width, height), color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::fillRect(const IntRect &rect, const Vec4 &color)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->fillRect(rect, color);
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::gradientFillRect(int x, int y,
 | 
			
		||||
                              int width, int height,
 | 
			
		||||
                              const Vec4 &color1, const Vec4 &color2,
 | 
			
		||||
                              bool vertical)
 | 
			
		||||
{
 | 
			
		||||
	gradientFillRect(IntRect(x, y, width, height), color1, color2, vertical);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::gradientFillRect(const IntRect &rect,
 | 
			
		||||
                              const Vec4 &color1, const Vec4 &color2,
 | 
			
		||||
                              bool vertical)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	flush();
 | 
			
		||||
 | 
			
		||||
	Quad quad;
 | 
			
		||||
 | 
			
		||||
	if (vertical)
 | 
			
		||||
	{
 | 
			
		||||
		quad.vert[0].color = color2;
 | 
			
		||||
		quad.vert[1].color = color2;
 | 
			
		||||
		quad.vert[2].color = color1;
 | 
			
		||||
		quad.vert[3].color = color1;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		quad.vert[0].color = color1;
 | 
			
		||||
		quad.vert[3].color = color1;
 | 
			
		||||
		quad.vert[1].color = color2;
 | 
			
		||||
		quad.vert[2].color = color2;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quad.setPosRect(rect);
 | 
			
		||||
 | 
			
		||||
	Tex::unbind();
 | 
			
		||||
	p->bindFBO();
 | 
			
		||||
	p->pushSetViewport();
 | 
			
		||||
 | 
			
		||||
	p->blitQuad(quad);
 | 
			
		||||
 | 
			
		||||
	p->popViewport();
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::clearRect(int x, int y, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	clearRect(IntRect(x, y, width, height));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::clearRect(const IntRect &rect)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->fillRect(rect, Vec4());
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::clear()
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	/* Any queued points won't be visible after this anyway */
 | 
			
		||||
	p->pointArray.reset();
 | 
			
		||||
 | 
			
		||||
	p->bindFBO();
 | 
			
		||||
 | 
			
		||||
	glState.clearColor.pushSet(Vec4());
 | 
			
		||||
 | 
			
		||||
	glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
	glState.clearColor.pop();
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Vec4 Bitmap::getPixel(int x, int y) const
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED;
 | 
			
		||||
 | 
			
		||||
	if (x < 0 || y < 0 || x >= width() || y >= height())
 | 
			
		||||
		return Vec4();
 | 
			
		||||
 | 
			
		||||
	flush();
 | 
			
		||||
 | 
			
		||||
	p->bindFBO();
 | 
			
		||||
 | 
			
		||||
	glState.viewport.push();
 | 
			
		||||
	Vec4 pixel = FBO::getPixel(x, y, width(), height());
 | 
			
		||||
	glState.viewport.pop();
 | 
			
		||||
 | 
			
		||||
	return pixel;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::setPixel(int x, int y, const Vec4 &color)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->pointArray.append(Vec2(x+.5, y+.5), color);
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::hueChange(int hue)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if ((hue % 360) == 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	flush();
 | 
			
		||||
 | 
			
		||||
	TexFBO newTex = gState->texPool().request(width(), height());
 | 
			
		||||
 | 
			
		||||
	FloatRect texRect(rect());
 | 
			
		||||
 | 
			
		||||
	Quad quad;
 | 
			
		||||
	quad.setTexPosRect(texRect, texRect);
 | 
			
		||||
 | 
			
		||||
	/* Calculate hue parameter */
 | 
			
		||||
	hue = wrapRange(hue, 0, 359);
 | 
			
		||||
	float hueAdj = -((M_PI * 2) / 360) * hue;
 | 
			
		||||
 | 
			
		||||
	HueShader &shader = gState->hueShader();
 | 
			
		||||
	shader.bind();
 | 
			
		||||
	shader.setHueAdjust(hueAdj);
 | 
			
		||||
	shader.setInputTexture(p->tex.tex);
 | 
			
		||||
 | 
			
		||||
	FBO::bind(newTex.fbo);
 | 
			
		||||
	Tex::bindMatrix(width(), height());
 | 
			
		||||
	p->pushSetViewport();
 | 
			
		||||
 | 
			
		||||
	p->blitQuad(quad);
 | 
			
		||||
 | 
			
		||||
	shader.unbind();
 | 
			
		||||
 | 
			
		||||
	p->popViewport();
 | 
			
		||||
 | 
			
		||||
	gState->texPool().release(p->tex);
 | 
			
		||||
	p->tex = newTex;
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::drawText(int x, int y,
 | 
			
		||||
                      int width, int height,
 | 
			
		||||
                      const char *str, int align)
 | 
			
		||||
{
 | 
			
		||||
	drawText(IntRect(x, y, width, height), str, align);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::drawText(const IntRect &rect, const char *str, int align)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (*str == '\0')
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	flush();
 | 
			
		||||
 | 
			
		||||
	TTF_Font *font = p->font->getSdlFont();
 | 
			
		||||
 | 
			
		||||
	SDL_Color c;
 | 
			
		||||
	p->font->getColor()->toSDLColor(c);
 | 
			
		||||
 | 
			
		||||
	SDL_Surface *txtSurf;
 | 
			
		||||
 | 
			
		||||
	if (gState->rtData().config.solidFonts)
 | 
			
		||||
		txtSurf = TTF_RenderUTF8_Solid(font, str, c);
 | 
			
		||||
	else
 | 
			
		||||
		txtSurf = TTF_RenderUTF8_Blended(font, str, c);
 | 
			
		||||
 | 
			
		||||
	p->ensureFormat(txtSurf, SDL_PIXELFORMAT_ARGB8888);
 | 
			
		||||
 | 
			
		||||
	int alignX = rect.x;
 | 
			
		||||
 | 
			
		||||
	switch (align)
 | 
			
		||||
	{
 | 
			
		||||
	default:
 | 
			
		||||
	case Left :
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Center :
 | 
			
		||||
		alignX += (rect.w - txtSurf->w) / 2;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case Right :
 | 
			
		||||
		alignX += rect.w - txtSurf->w;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (alignX < rect.x)
 | 
			
		||||
		alignX = rect.x;
 | 
			
		||||
 | 
			
		||||
	int alignY = rect.y + (rect.h - txtSurf->h) / 2;
 | 
			
		||||
 | 
			
		||||
	float squeeze = (float) rect.w / txtSurf->w;
 | 
			
		||||
 | 
			
		||||
	if (squeeze > 1)
 | 
			
		||||
		squeeze = 1;
 | 
			
		||||
 | 
			
		||||
	FloatRect posRect(alignX, alignY, txtSurf->w * squeeze, txtSurf->h);
 | 
			
		||||
 | 
			
		||||
	Vec2 gpTexSize;
 | 
			
		||||
	gState->ensureTexSize(txtSurf->w, txtSurf->h, gpTexSize);
 | 
			
		||||
 | 
			
		||||
//	if (str[1] != '\0')
 | 
			
		||||
	{
 | 
			
		||||
		/* Aquire a partial copy of the destination
 | 
			
		||||
		 * buffer we're about to render to */
 | 
			
		||||
		TexFBO &gpTex2 = gState->gpTexFBO(posRect.w, posRect.h);
 | 
			
		||||
 | 
			
		||||
		FBO::bind(gpTex2.fbo, FBO::Draw);
 | 
			
		||||
		FBO::bind(p->tex.fbo, FBO::Read);
 | 
			
		||||
		FBO::blit(posRect.x, posRect.y, 0, 0, posRect.w, posRect.h);
 | 
			
		||||
 | 
			
		||||
		FloatRect bltRect(0, 0,
 | 
			
		||||
		                  gpTexSize.x / gpTex2.width,
 | 
			
		||||
		                  gpTexSize.y / gpTex2.height);
 | 
			
		||||
 | 
			
		||||
		BltShader &shader = gState->bltShader();
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.setSource();
 | 
			
		||||
		shader.setDestination(gpTex2.tex);
 | 
			
		||||
		shader.setSubRect(bltRect);
 | 
			
		||||
		shader.setOpacity(p->font->getColor()->norm.w);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	gState->bindTex();
 | 
			
		||||
	Tex::uploadSubImage(0, 0, txtSurf->w, txtSurf->h, txtSurf->pixels, GL_BGRA);
 | 
			
		||||
	Tex::setSmooth(true);
 | 
			
		||||
 | 
			
		||||
	Quad quad;
 | 
			
		||||
	quad.setTexRect(FloatRect(0, 0, txtSurf->w, txtSurf->h));
 | 
			
		||||
	quad.setPosRect(posRect);
 | 
			
		||||
	SDL_FreeSurface(txtSurf);
 | 
			
		||||
 | 
			
		||||
	p->bindFBO();
 | 
			
		||||
	p->pushSetViewport();
 | 
			
		||||
	glState.blendMode.pushSet(BlendNone);
 | 
			
		||||
 | 
			
		||||
	quad.draw();
 | 
			
		||||
 | 
			
		||||
	glState.blendMode.pop();
 | 
			
		||||
	p->popViewport();
 | 
			
		||||
 | 
			
		||||
	FragShader::unbind();
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IntRect Bitmap::textSize(const char *str)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	TTF_Font *font = p->font->getSdlFont();
 | 
			
		||||
 | 
			
		||||
	int w, h;
 | 
			
		||||
	TTF_SizeUTF8(font, str, &w, &h);
 | 
			
		||||
 | 
			
		||||
//	if (strlen(str) == 1)
 | 
			
		||||
//		TTF_GlyphMetrics(font, *str, 0, 0, 0, 0, &w);
 | 
			
		||||
 | 
			
		||||
	return IntRect(0, 0, w, h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE(Bitmap, Font, Font*, p->font)
 | 
			
		||||
 | 
			
		||||
void Bitmap::flush() const
 | 
			
		||||
{
 | 
			
		||||
	p->flushPoints();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TexFBO &Bitmap::getGLTypes()
 | 
			
		||||
{
 | 
			
		||||
	return p->tex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Bitmap::bindTexWithMatrix()
 | 
			
		||||
{
 | 
			
		||||
	p->bindTextureWithMatrix();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Bitmap::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
	gState->texPool().release(p->tex);
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										115
									
								
								src/bitmap.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/bitmap.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,115 @@
 | 
			
		|||
/*
 | 
			
		||||
** bitmap.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef BITMAP_H
 | 
			
		||||
#define BITMAP_H
 | 
			
		||||
 | 
			
		||||
#include "disposable.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
 | 
			
		||||
#include "sigc++/signal.h"
 | 
			
		||||
 | 
			
		||||
class Font;
 | 
			
		||||
struct TexFBO;
 | 
			
		||||
 | 
			
		||||
struct BitmapPrivate;
 | 
			
		||||
// FIXME make this class use proper RGSS classes again
 | 
			
		||||
class Bitmap : public Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Bitmap(const char *filename);
 | 
			
		||||
	Bitmap(int width, int height);
 | 
			
		||||
	/* Clone constructor */
 | 
			
		||||
	Bitmap(const Bitmap &other);
 | 
			
		||||
	~Bitmap();
 | 
			
		||||
 | 
			
		||||
	int width()  const;
 | 
			
		||||
	int height() const;
 | 
			
		||||
	IntRect rect() const;
 | 
			
		||||
 | 
			
		||||
	void blt(int x, int y,
 | 
			
		||||
	         const Bitmap &source, const IntRect &rect,
 | 
			
		||||
	         int opacity = 255);
 | 
			
		||||
 | 
			
		||||
	void stretchBlt(const IntRect &destRect,
 | 
			
		||||
	                const Bitmap &source, const IntRect &sourceRect,
 | 
			
		||||
	                int opacity = 255);
 | 
			
		||||
 | 
			
		||||
	void fillRect(int x, int y,
 | 
			
		||||
	              int width, int height,
 | 
			
		||||
	              const Vec4 &color);
 | 
			
		||||
	void fillRect(const IntRect &rect, const Vec4 &color);
 | 
			
		||||
 | 
			
		||||
	/* RGSS2 */
 | 
			
		||||
	void gradientFillRect(int x, int y,
 | 
			
		||||
	                      int width, int height,
 | 
			
		||||
	                      const Vec4 &color1, const Vec4 &color2,
 | 
			
		||||
	                      bool vertical = false);
 | 
			
		||||
	void gradientFillRect(const IntRect &rect,
 | 
			
		||||
	                      const Vec4 &color1, const Vec4 &color2,
 | 
			
		||||
	                      bool vertical = false);
 | 
			
		||||
 | 
			
		||||
	void clearRect(int x, int y,
 | 
			
		||||
	               int width, int height);
 | 
			
		||||
	void clearRect(const IntRect &rect);
 | 
			
		||||
 | 
			
		||||
//	void radialBlur(int angle, int divisions);
 | 
			
		||||
//	/* ----- */
 | 
			
		||||
 | 
			
		||||
	void clear();
 | 
			
		||||
 | 
			
		||||
	Vec4 getPixel(int x, int y) const;
 | 
			
		||||
	void setPixel(int x, int y, const Vec4 &color);
 | 
			
		||||
 | 
			
		||||
	void hueChange(int hue);
 | 
			
		||||
 | 
			
		||||
	enum TextAlign
 | 
			
		||||
	{
 | 
			
		||||
		Left = 0,
 | 
			
		||||
		Center = 1,
 | 
			
		||||
		Right = 2
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	void drawText(int x, int y,
 | 
			
		||||
	              int width, int height,
 | 
			
		||||
	              const char *str, int align = Left);
 | 
			
		||||
 | 
			
		||||
	void drawText(const IntRect &rect,
 | 
			
		||||
	              const char *str, int align = Left);
 | 
			
		||||
 | 
			
		||||
	IntRect textSize(const char *str);
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR(Font, Font*)
 | 
			
		||||
 | 
			
		||||
	void flush() const;
 | 
			
		||||
	TexFBO &getGLTypes();
 | 
			
		||||
	void bindTexWithMatrix();
 | 
			
		||||
 | 
			
		||||
	sigc::signal<void> modified;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void releaseResources();
 | 
			
		||||
 | 
			
		||||
	BitmapPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // BITMAP_H
 | 
			
		||||
							
								
								
									
										87
									
								
								src/config.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								src/config.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
/*
 | 
			
		||||
** config.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
 | 
			
		||||
#include <QSettings>
 | 
			
		||||
#include <QFileInfo>
 | 
			
		||||
#include <QString>
 | 
			
		||||
#include <QStringList>
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#include <QRegExp>
 | 
			
		||||
 | 
			
		||||
Config::Config()
 | 
			
		||||
    : debugMode(false),
 | 
			
		||||
      winResizable(false),
 | 
			
		||||
      fullscreen(false),
 | 
			
		||||
      vsync(false),
 | 
			
		||||
      defScreenW(640),
 | 
			
		||||
      defScreenH(480),
 | 
			
		||||
      solidFonts(false),
 | 
			
		||||
      gameFolder(".")
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
void Config::read()
 | 
			
		||||
{
 | 
			
		||||
	QSettings confFile("mkxp.conf", QSettings::IniFormat);
 | 
			
		||||
 | 
			
		||||
#define READ_VAL(key, Type) key = confFile.value(#key, key).to##Type()
 | 
			
		||||
 | 
			
		||||
	READ_VAL(debugMode, Bool);
 | 
			
		||||
	READ_VAL(winResizable, Bool);
 | 
			
		||||
	READ_VAL(fullscreen, Bool);
 | 
			
		||||
	READ_VAL(vsync, Bool);
 | 
			
		||||
	READ_VAL(defScreenW, Int);
 | 
			
		||||
	READ_VAL(defScreenH, Int);
 | 
			
		||||
	READ_VAL(solidFonts,  Bool);
 | 
			
		||||
	READ_VAL(gameFolder, ByteArray);
 | 
			
		||||
	READ_VAL(customScript, ByteArray);
 | 
			
		||||
 | 
			
		||||
	QStringList _rtps = confFile.value("RTPs").toStringList();
 | 
			
		||||
	Q_FOREACH(const QString &s, _rtps)
 | 
			
		||||
		rtps << s.toUtf8();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Config::readGameINI()
 | 
			
		||||
{
 | 
			
		||||
	if (!customScript.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		game.title = basename(customScript.constData());
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	QSettings gameINI(gameFolder + "/Game.ini", QSettings::IniFormat);
 | 
			
		||||
	QFileInfo finfo(gameFolder.constData());
 | 
			
		||||
	game.title = gameINI.value("Game/Title", finfo.baseName()).toByteArray();
 | 
			
		||||
 | 
			
		||||
	/* Gotta read the "Scripts" entry manually because Qt can't handle '\' */
 | 
			
		||||
	QFile gameINIFile(gameFolder + "/Game.ini");
 | 
			
		||||
	if (gameINIFile.open(QFile::ReadOnly))
 | 
			
		||||
	{
 | 
			
		||||
		QString gameINIContents = gameINIFile.readAll();
 | 
			
		||||
		QRegExp scriptsRE(".*Scripts=(.*)\r\nTitle=.*");
 | 
			
		||||
		if (scriptsRE.exactMatch(gameINIContents))
 | 
			
		||||
		{
 | 
			
		||||
			game.scripts = scriptsRE.cap(1).toUtf8();
 | 
			
		||||
			game.scripts.replace('\\', '/');
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										58
									
								
								src/config.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/config.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
/*
 | 
			
		||||
** config.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_H
 | 
			
		||||
#define CONFIG_H
 | 
			
		||||
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QVector>
 | 
			
		||||
 | 
			
		||||
struct Config
 | 
			
		||||
{
 | 
			
		||||
	bool debugMode;
 | 
			
		||||
 | 
			
		||||
	bool winResizable;
 | 
			
		||||
	bool fullscreen;
 | 
			
		||||
	bool vsync;
 | 
			
		||||
 | 
			
		||||
	int defScreenW;
 | 
			
		||||
	int defScreenH;
 | 
			
		||||
 | 
			
		||||
	bool solidFonts;
 | 
			
		||||
 | 
			
		||||
	QByteArray gameFolder;
 | 
			
		||||
 | 
			
		||||
	QByteArray customScript;
 | 
			
		||||
	QVector<QByteArray> rtps;
 | 
			
		||||
 | 
			
		||||
	/* Game INI contents */
 | 
			
		||||
	struct {
 | 
			
		||||
		QByteArray scripts;
 | 
			
		||||
		QByteArray title;
 | 
			
		||||
	} game;
 | 
			
		||||
 | 
			
		||||
	Config();
 | 
			
		||||
 | 
			
		||||
	void read();
 | 
			
		||||
	void readGameINI();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // CONFIG_H
 | 
			
		||||
							
								
								
									
										123
									
								
								src/debuglogger.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								src/debuglogger.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,123 @@
 | 
			
		|||
/*
 | 
			
		||||
** debuglogger.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "debuglogger.h"
 | 
			
		||||
 | 
			
		||||
#include "GL/glew.h"
 | 
			
		||||
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#include <QTime>
 | 
			
		||||
#include <QTextStream>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
struct DebugLoggerPrivate
 | 
			
		||||
{
 | 
			
		||||
	QFile logFile;
 | 
			
		||||
	QTextStream *stream;
 | 
			
		||||
 | 
			
		||||
	DebugLoggerPrivate(const char *logFilename)
 | 
			
		||||
	{
 | 
			
		||||
		if (logFilename)
 | 
			
		||||
		{
 | 
			
		||||
			logFile.setFileName(logFilename);
 | 
			
		||||
			logFile.open(QFile::WriteOnly);
 | 
			
		||||
			stream = new QTextStream(&logFile);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			stream = new QTextStream(stderr, QIODevice::WriteOnly);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~DebugLoggerPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		delete stream;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void writeTimestamp()
 | 
			
		||||
	{
 | 
			
		||||
		QTime time = QTime::currentTime();
 | 
			
		||||
		*stream << "[" << time.toString().toAscii() << "] ";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void writeLine(const char *line)
 | 
			
		||||
	{
 | 
			
		||||
		*stream << line << "\n";
 | 
			
		||||
		stream->flush();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void amdDebugFunc(GLuint id,
 | 
			
		||||
                         GLenum category,
 | 
			
		||||
	                     GLenum severity,
 | 
			
		||||
	                     GLsizei length,
 | 
			
		||||
	                     const GLchar* message,
 | 
			
		||||
	                     GLvoid* userParam)
 | 
			
		||||
{
 | 
			
		||||
	DebugLoggerPrivate *p = static_cast<DebugLoggerPrivate*>(userParam);
 | 
			
		||||
 | 
			
		||||
	(void) id;
 | 
			
		||||
	(void) category;
 | 
			
		||||
	(void) severity;
 | 
			
		||||
	(void) length;
 | 
			
		||||
 | 
			
		||||
	p->writeTimestamp();
 | 
			
		||||
	p->writeLine(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void arbDebugFunc(GLenum source,
 | 
			
		||||
                         GLenum type,
 | 
			
		||||
                         GLuint id,
 | 
			
		||||
                         GLenum severity,
 | 
			
		||||
                         GLsizei length,
 | 
			
		||||
                         const GLchar* message,
 | 
			
		||||
                         GLvoid* userParam)
 | 
			
		||||
{
 | 
			
		||||
	DebugLoggerPrivate *p = static_cast<DebugLoggerPrivate*>(userParam);
 | 
			
		||||
 | 
			
		||||
	(void) source;
 | 
			
		||||
	(void) type;
 | 
			
		||||
	(void) id;
 | 
			
		||||
	(void) severity;
 | 
			
		||||
	(void) length;
 | 
			
		||||
 | 
			
		||||
	p->writeTimestamp();
 | 
			
		||||
	p->writeLine(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DebugLogger::DebugLogger(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	p = new DebugLoggerPrivate(filename);
 | 
			
		||||
 | 
			
		||||
	if (GLEW_KHR_debug)
 | 
			
		||||
		glDebugMessageCallback(arbDebugFunc, p);
 | 
			
		||||
	else if (GLEW_ARB_debug_output)
 | 
			
		||||
		glDebugMessageCallbackARB(arbDebugFunc, p);
 | 
			
		||||
	else if (GLEW_AMD_debug_output)
 | 
			
		||||
		glDebugMessageCallbackAMD(amdDebugFunc, p);
 | 
			
		||||
	else
 | 
			
		||||
		qDebug() << "DebugLogger: no debug extensions found";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DebugLogger::~DebugLogger()
 | 
			
		||||
{
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/debuglogger.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/debuglogger.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
/*
 | 
			
		||||
** debuglogger.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef DEBUGLOGGER_H
 | 
			
		||||
#define DEBUGLOGGER_H
 | 
			
		||||
 | 
			
		||||
struct DebugLoggerPrivate;
 | 
			
		||||
 | 
			
		||||
class DebugLogger
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	DebugLogger(const char *filename = 0);
 | 
			
		||||
	~DebugLogger();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	DebugLoggerPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // DEBUGLOGGER_H
 | 
			
		||||
							
								
								
									
										63
									
								
								src/disposable.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/disposable.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
/*
 | 
			
		||||
** disposable.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef DISPOSABLE_H
 | 
			
		||||
#define DISPOSABLE_H
 | 
			
		||||
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include "sigc++/signal.h"
 | 
			
		||||
 | 
			
		||||
class Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Disposable()
 | 
			
		||||
		: disposed(false)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	virtual ~Disposable() {}
 | 
			
		||||
 | 
			
		||||
	void dispose()
 | 
			
		||||
	{
 | 
			
		||||
		if (disposed)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		releaseResources();
 | 
			
		||||
		disposed = true;
 | 
			
		||||
		wasDisposed();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool isDisposed() const { return disposed; }
 | 
			
		||||
 | 
			
		||||
	sigc::signal<void> wasDisposed;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	virtual void releaseResources() = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	bool disposed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Every cpp needs to define DISP_CLASS_NAME for itself (lowercase) */
 | 
			
		||||
#define GUARD_DISPOSED \
 | 
			
		||||
{ if (isDisposed()) throw Exception(Exception::RGSSError, "disposed %S", DISP_CLASS_NAME); }
 | 
			
		||||
 | 
			
		||||
#endif // DISPOSABLE_H
 | 
			
		||||
							
								
								
									
										251
									
								
								src/etc-internal.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										251
									
								
								src/etc-internal.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,251 @@
 | 
			
		|||
/*
 | 
			
		||||
** etc-internal.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef ETC_TYPES_H
 | 
			
		||||
#define ETC_TYPES_H
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
struct Vec2
 | 
			
		||||
{
 | 
			
		||||
	float x, y;
 | 
			
		||||
 | 
			
		||||
	Vec2()
 | 
			
		||||
	    : x(0), y(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Vec2(float x, float y)
 | 
			
		||||
	    : x(x), y(y)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool operator==(const Vec2 &other) const
 | 
			
		||||
	{
 | 
			
		||||
		return (x == other.x && y == other.y);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Vec4
 | 
			
		||||
{
 | 
			
		||||
	float x, y, z, w;
 | 
			
		||||
 | 
			
		||||
	Vec4()
 | 
			
		||||
	    : x(0), y(0), z(0), w(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Vec4(float x, float y, float z, float w)
 | 
			
		||||
	    : x(x), y(y), z(z), w(w)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool operator==(const Vec4 &other) const
 | 
			
		||||
	{
 | 
			
		||||
		return (x == other.x && y == other.y && z == other.z && w == other.w);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Vec2i
 | 
			
		||||
{
 | 
			
		||||
	int x, y;
 | 
			
		||||
 | 
			
		||||
	Vec2i()
 | 
			
		||||
	    : x(0), y(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Vec2i(int x, int y)
 | 
			
		||||
	    : x(x), y(y)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool operator==(const Vec2i &other)
 | 
			
		||||
	{
 | 
			
		||||
		return x == other.x && y == other.y;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Simple Vertex */
 | 
			
		||||
struct SVertex
 | 
			
		||||
{
 | 
			
		||||
	Vec2 pos;
 | 
			
		||||
	Vec2 texPos;
 | 
			
		||||
 | 
			
		||||
	static const void *posOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const void *texPosOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) sizeof(Vec2);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Color Vertex */
 | 
			
		||||
struct CVertex
 | 
			
		||||
{
 | 
			
		||||
	Vec2 pos;
 | 
			
		||||
	Vec4 color;
 | 
			
		||||
 | 
			
		||||
	CVertex()
 | 
			
		||||
	    : color(1, 1, 1, 1)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	static const void *posOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const void *colorOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) sizeof(pos);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Vertex
 | 
			
		||||
{
 | 
			
		||||
	Vec2 pos;
 | 
			
		||||
	Vec2 texPos;
 | 
			
		||||
	Vec4 color;
 | 
			
		||||
 | 
			
		||||
	Vertex()
 | 
			
		||||
	    : color(1, 1, 1, 1)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	static const void *posOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const void *texPosOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) sizeof(Vec2);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static const void *colorOffset()
 | 
			
		||||
	{
 | 
			
		||||
		return (const void*) sizeof(SVertex);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IntRect
 | 
			
		||||
{
 | 
			
		||||
	int x, y, w, h;
 | 
			
		||||
 | 
			
		||||
	IntRect()
 | 
			
		||||
	    : x(0), y(0), w(0), h(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	IntRect(int x, int y, int w, int h)
 | 
			
		||||
	    : x(x), y(y), w(w), h(h)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool operator==(const IntRect &other) const
 | 
			
		||||
	{
 | 
			
		||||
		return (x == other.x && y == other.y &&
 | 
			
		||||
		        w == other.w && h == other.h);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct StaticRect { float x, y, w, h; };
 | 
			
		||||
 | 
			
		||||
struct FloatRect
 | 
			
		||||
{
 | 
			
		||||
	float x, y, w, h;
 | 
			
		||||
 | 
			
		||||
	FloatRect()
 | 
			
		||||
	    : x(0), y(0), w(0), h(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	FloatRect(float x, float y, float w, float h)
 | 
			
		||||
	    : x(x), y(y), w(w), h(h)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	FloatRect(const StaticRect &d)
 | 
			
		||||
	    : x(d.x), y(d.y), w(d.w), h(d.h)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	FloatRect(const IntRect &r)
 | 
			
		||||
	    : x(r.x), y(r.y), w(r.w), h(r.h)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Vec2 topLeft() const { return Vec2(x, y); }
 | 
			
		||||
	Vec2 bottomLeft() const { return Vec2(x, y+h); }
 | 
			
		||||
	Vec2 topRight() const { return Vec2(x+w, y); }
 | 
			
		||||
	Vec2 bottomRight() const { return Vec2(x+w, y+h); }
 | 
			
		||||
 | 
			
		||||
	void shrinkHalf()
 | 
			
		||||
	{
 | 
			
		||||
		x += 0.5;
 | 
			
		||||
		y += 0.5;
 | 
			
		||||
		w -= 1.0;
 | 
			
		||||
		h -= 1.0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FloatRect vFlipped() const
 | 
			
		||||
	{
 | 
			
		||||
		return FloatRect(x, y+h, w, -h);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FloatRect hFlipped() const
 | 
			
		||||
	{
 | 
			
		||||
		return FloatRect(x+w, y, -w, h);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2 corner(int i) const
 | 
			
		||||
	{
 | 
			
		||||
		switch (i)
 | 
			
		||||
		{
 | 
			
		||||
		case 0 : return topLeft();
 | 
			
		||||
		case 1 : return topRight();
 | 
			
		||||
		case 2 : return bottomRight();
 | 
			
		||||
		case 3 : return bottomLeft();
 | 
			
		||||
		default : return Vec2();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Value between 0 and 255 with internal
 | 
			
		||||
 * normalized representation */
 | 
			
		||||
struct NormValue
 | 
			
		||||
{
 | 
			
		||||
	int unNorm;
 | 
			
		||||
	float norm;
 | 
			
		||||
 | 
			
		||||
	NormValue()
 | 
			
		||||
	    : unNorm(0),
 | 
			
		||||
	      norm(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	NormValue(int unNorm)
 | 
			
		||||
	    : unNorm(unNorm),
 | 
			
		||||
	      norm(unNorm / 255.0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void operator =(int value)
 | 
			
		||||
	{
 | 
			
		||||
		unNorm = bound(value, 0, 255);
 | 
			
		||||
		norm = unNorm / 255.0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	operator int() const
 | 
			
		||||
	{
 | 
			
		||||
		return unNorm;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // ETC_TYPES_H
 | 
			
		||||
							
								
								
									
										316
									
								
								src/etc.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								src/etc.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,316 @@
 | 
			
		|||
/*
 | 
			
		||||
** etc.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
 | 
			
		||||
#include "serial-util.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_types.h"
 | 
			
		||||
#include "SDL2/SDL_pixels.h"
 | 
			
		||||
 | 
			
		||||
Color::Color(double red, double green, double blue, double alpha)
 | 
			
		||||
	: red(red), green(green), blue(blue), alpha(alpha)
 | 
			
		||||
{
 | 
			
		||||
	updateInternal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Color::Color(const Vec4 &norm)
 | 
			
		||||
	: norm(norm)
 | 
			
		||||
{
 | 
			
		||||
	updateExternal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Color::Color(const Color &o)
 | 
			
		||||
    : red(o.red), green(o.green), blue(o.blue), alpha(o.alpha),
 | 
			
		||||
      norm(o.norm)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
bool Color::operator==(const Color &o) const
 | 
			
		||||
{
 | 
			
		||||
	return red   == o.red   &&
 | 
			
		||||
	       green == o.green &&
 | 
			
		||||
	       blue  == o.blue  &&
 | 
			
		||||
	       alpha == o.alpha;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::updateInternal()
 | 
			
		||||
{
 | 
			
		||||
	norm.x = red   / 255;
 | 
			
		||||
	norm.y = green / 255;
 | 
			
		||||
	norm.z = blue  / 255;
 | 
			
		||||
	norm.w = alpha / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::updateExternal()
 | 
			
		||||
{
 | 
			
		||||
	red   = norm.x * 255;
 | 
			
		||||
	green = norm.y * 255;
 | 
			
		||||
	blue  = norm.z * 255;
 | 
			
		||||
	alpha = norm.w * 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::set(double red, double green, double blue, double alpha)
 | 
			
		||||
{
 | 
			
		||||
	this->red   = red;
 | 
			
		||||
	this->green = green;
 | 
			
		||||
	this->blue  = blue;
 | 
			
		||||
	this->alpha = alpha;
 | 
			
		||||
 | 
			
		||||
	updateInternal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::setRed(double value)
 | 
			
		||||
{
 | 
			
		||||
	red = value;
 | 
			
		||||
	norm.x = bound<double>(value, 0, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::setGreen(double value)
 | 
			
		||||
{
 | 
			
		||||
	green = value;
 | 
			
		||||
	norm.y = bound<double>(value, 0, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::setBlue(double value)
 | 
			
		||||
{
 | 
			
		||||
	blue = value;
 | 
			
		||||
	norm.z = bound<double>(value, 0, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::setAlpha(double value)
 | 
			
		||||
{
 | 
			
		||||
	alpha = value;
 | 
			
		||||
	norm.w = bound<double>(value, 0, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::toSDLColor(SDL_Color &c) const
 | 
			
		||||
{
 | 
			
		||||
	c.r = bound<double>(red, 0, 255);
 | 
			
		||||
	c.g = bound<double>(green, 0, 255);
 | 
			
		||||
	c.b = bound<double>(blue, 0, 255);
 | 
			
		||||
//	c.a = bound<double>(alpha, 0, 255);
 | 
			
		||||
	c.a = 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Serializable */
 | 
			
		||||
int Color::serialSize() const
 | 
			
		||||
{
 | 
			
		||||
	return 4 * 8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Color::serialize(char *buffer) const
 | 
			
		||||
{
 | 
			
		||||
	char *buf = buffer;
 | 
			
		||||
 | 
			
		||||
	write_double(&buf, red);
 | 
			
		||||
	write_double(&buf, green);
 | 
			
		||||
	write_double(&buf, blue);
 | 
			
		||||
	write_double(&buf, alpha);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Color *Color::deserialize(const char *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	if (len != 32)
 | 
			
		||||
		throw Exception(Exception::ArgumentError, "Color: Serialized data invalid");
 | 
			
		||||
 | 
			
		||||
	Color *c = new Color();
 | 
			
		||||
	uint i = 0;
 | 
			
		||||
 | 
			
		||||
	c->red   = read_double(data, i);
 | 
			
		||||
	c->green = read_double(data, i);
 | 
			
		||||
	c->blue  = read_double(data, i);
 | 
			
		||||
	c->alpha = read_double(data, i);
 | 
			
		||||
	c->updateInternal();
 | 
			
		||||
 | 
			
		||||
	return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Tone::Tone(double red, double green, double blue, double gray)
 | 
			
		||||
	: red(red), green(green), blue(blue), gray(gray)
 | 
			
		||||
{
 | 
			
		||||
	updateInternal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Tone::Tone(const Tone &o)
 | 
			
		||||
    : red(o.red), green(o.green), blue(o.blue), gray(o.gray),
 | 
			
		||||
      norm(o.norm)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
bool Tone::operator==(const Tone &o) const
 | 
			
		||||
{
 | 
			
		||||
	return red   == o.red   &&
 | 
			
		||||
	       green == o.green &&
 | 
			
		||||
	       blue  == o.blue  &&
 | 
			
		||||
	       gray  == o.gray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::updateInternal()
 | 
			
		||||
{
 | 
			
		||||
	norm.x = (float) bound<double>(red,   -255, 255) / 255;
 | 
			
		||||
	norm.y = (float) bound<double>(green, -255, 255) / 255;
 | 
			
		||||
	norm.z = (float) bound<double>(blue,  -255, 255) / 255;
 | 
			
		||||
	norm.w = (float) bound<double>(gray,     0, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::set(double red, double green, double blue, double gray)
 | 
			
		||||
{
 | 
			
		||||
	this->red   = red;
 | 
			
		||||
	this->green = green;
 | 
			
		||||
	this->blue  = blue;
 | 
			
		||||
	this->gray  = gray;
 | 
			
		||||
 | 
			
		||||
	updateInternal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::setRed(double value)
 | 
			
		||||
{
 | 
			
		||||
	red = value;
 | 
			
		||||
	norm.x = (float) bound<double>(value, -255, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::setGreen(double value)
 | 
			
		||||
{
 | 
			
		||||
	green = value;
 | 
			
		||||
	norm.y = (float) bound<double>(value, -255, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::setBlue(double value)
 | 
			
		||||
{
 | 
			
		||||
	blue = value;
 | 
			
		||||
	norm.z = (float) bound<double>(value, -255, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::setGray(double value)
 | 
			
		||||
{
 | 
			
		||||
	gray = value;
 | 
			
		||||
	norm.w = (float) bound<double>(value, 0, 255) / 255;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Serializable */
 | 
			
		||||
int Tone::serialSize() const
 | 
			
		||||
{
 | 
			
		||||
	return 4 * 8;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Tone::serialize(char *buffer) const
 | 
			
		||||
{
 | 
			
		||||
	char *buf = buffer;
 | 
			
		||||
 | 
			
		||||
	write_double(&buf, red);
 | 
			
		||||
	write_double(&buf, green);
 | 
			
		||||
	write_double(&buf, blue);
 | 
			
		||||
	write_double(&buf, gray);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Tone *Tone::deserialize(const char *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	if (len != 32)
 | 
			
		||||
		throw Exception(Exception::ArgumentError, "Tone: Serialized data invalid");
 | 
			
		||||
 | 
			
		||||
	Tone *t = new Tone();
 | 
			
		||||
	uint i = 0;
 | 
			
		||||
 | 
			
		||||
	t->red   = read_double(data, i);
 | 
			
		||||
	t->green = read_double(data, i);
 | 
			
		||||
	t->blue  = read_double(data, i);
 | 
			
		||||
	t->gray  = read_double(data, i);
 | 
			
		||||
	t->updateInternal();
 | 
			
		||||
 | 
			
		||||
	return t;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Rect::Rect(int x, int y, int width, int height)
 | 
			
		||||
    : x(x), y(y), width(width), height(height)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
Rect::Rect(const Rect &o)
 | 
			
		||||
    : x(o.x), y(o.y),
 | 
			
		||||
      width(o.width), height(o.height)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
Rect::Rect(const IntRect &r)
 | 
			
		||||
    : x(r.x), y(r.y), width(r.w), height(r.h)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
bool Rect::operator==(const Rect &o) const
 | 
			
		||||
{
 | 
			
		||||
	return x      == o.x     &&
 | 
			
		||||
	       y      == o.y     &&
 | 
			
		||||
	       width  == o.width &&
 | 
			
		||||
	       height == o.height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Rect::operator=(const IntRect &rect)
 | 
			
		||||
{
 | 
			
		||||
	x = rect.x;
 | 
			
		||||
	y = rect.y;
 | 
			
		||||
	width = rect.w;
 | 
			
		||||
	height = rect.h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Rect::set(int x, int y, int w, int h)
 | 
			
		||||
{
 | 
			
		||||
	this->x = x;
 | 
			
		||||
	this->y = y;
 | 
			
		||||
	width = w;
 | 
			
		||||
	height = h;
 | 
			
		||||
	valueChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Rect::empty()
 | 
			
		||||
{
 | 
			
		||||
	x = y = width = height = 0;
 | 
			
		||||
	valueChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Rect::serialSize() const
 | 
			
		||||
{
 | 
			
		||||
	return 4 * 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Rect::serialize(char *buffer) const
 | 
			
		||||
{
 | 
			
		||||
	char *buf = buffer;
 | 
			
		||||
 | 
			
		||||
	write_int32(&buf, x);
 | 
			
		||||
	write_int32(&buf, y);
 | 
			
		||||
	write_int32(&buf, width);
 | 
			
		||||
	write_int32(&buf, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Rect *Rect::deserialize(const char *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	if (len != 16)
 | 
			
		||||
		throw Exception(Exception::ArgumentError, "Rect: Serialized data invalid");
 | 
			
		||||
 | 
			
		||||
	Rect *r = new Rect();
 | 
			
		||||
	uint i = 0;
 | 
			
		||||
 | 
			
		||||
	r->x      = read_int32(data, i);
 | 
			
		||||
	r->y      = read_int32(data, i);
 | 
			
		||||
	r->width  = read_int32(data, i);
 | 
			
		||||
	r->height = read_int32(data, i);
 | 
			
		||||
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										207
									
								
								src/etc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								src/etc.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,207 @@
 | 
			
		|||
/*
 | 
			
		||||
** etc.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef ETC_H
 | 
			
		||||
#define ETC_H
 | 
			
		||||
 | 
			
		||||
#include "sigc++/signal.h"
 | 
			
		||||
 | 
			
		||||
#include "serializable.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
 | 
			
		||||
struct SDL_Color;
 | 
			
		||||
 | 
			
		||||
enum BlendType
 | 
			
		||||
{
 | 
			
		||||
	BlendNone = -1, /* Only internal use */
 | 
			
		||||
 | 
			
		||||
	BlendNormal = 0,
 | 
			
		||||
	BlendAddition = 1,
 | 
			
		||||
	BlendSubstraction = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Color : public Serializable
 | 
			
		||||
{
 | 
			
		||||
	Color()
 | 
			
		||||
	    : red(0), green(0), blue(0), alpha(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Color(double red, double green, double blue, double alpha = 255);
 | 
			
		||||
	Color(const Vec4 &norm);
 | 
			
		||||
	Color(const Color &o);
 | 
			
		||||
 | 
			
		||||
	bool operator==(const Color &o) const;
 | 
			
		||||
 | 
			
		||||
	void updateInternal();
 | 
			
		||||
	void updateExternal();
 | 
			
		||||
 | 
			
		||||
	void set(double red, double green, double blue, double alpha);
 | 
			
		||||
	void setRed(double value);
 | 
			
		||||
	void setGreen(double value);
 | 
			
		||||
	void setBlue(double value);
 | 
			
		||||
	void setAlpha(double value);
 | 
			
		||||
 | 
			
		||||
	double getRed()   const { return red;   }
 | 
			
		||||
	double getGreen() const { return green; }
 | 
			
		||||
	double getBlue()  const { return blue;  }
 | 
			
		||||
	double getAlpha() const { return alpha; }
 | 
			
		||||
 | 
			
		||||
	bool hasEffect()
 | 
			
		||||
	{
 | 
			
		||||
		return (alpha != 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void toSDLColor(SDL_Color &c) const;
 | 
			
		||||
 | 
			
		||||
	/* Serializable */
 | 
			
		||||
	int serialSize() const;
 | 
			
		||||
	void serialize(char *buffer) const;
 | 
			
		||||
	static Color *deserialize(const char *data, int len);
 | 
			
		||||
 | 
			
		||||
	/* Range (0.0 ~ 255.0) */
 | 
			
		||||
	double red;
 | 
			
		||||
	double green;
 | 
			
		||||
	double blue;
 | 
			
		||||
	double alpha;
 | 
			
		||||
 | 
			
		||||
	/* Normalized (0.0 ~ 1.0) */
 | 
			
		||||
	Vec4 norm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Tone : public Serializable
 | 
			
		||||
{
 | 
			
		||||
	Tone()
 | 
			
		||||
	    : red(0), green(0), blue(0), gray(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Tone(double red, double green, double blue, double gray = 0);
 | 
			
		||||
	Tone(const Tone &o);
 | 
			
		||||
 | 
			
		||||
	bool operator==(const Tone &o) const;
 | 
			
		||||
 | 
			
		||||
	void updateInternal();
 | 
			
		||||
 | 
			
		||||
	void set(double red, double green, double blue, double gray);
 | 
			
		||||
	void setRed(double value);
 | 
			
		||||
	void setGreen(double value);
 | 
			
		||||
	void setBlue(double value);
 | 
			
		||||
	void setGray(double value);
 | 
			
		||||
 | 
			
		||||
	double getRed()   const { return red;   }
 | 
			
		||||
	double getGreen() const { return green; }
 | 
			
		||||
	double getBlue()  const { return blue;  }
 | 
			
		||||
	double getGray()  const { return gray;  }
 | 
			
		||||
 | 
			
		||||
	bool hasEffect()
 | 
			
		||||
	{
 | 
			
		||||
		return ((int)red   != 0 ||
 | 
			
		||||
				(int)green != 0 ||
 | 
			
		||||
				(int)blue  != 0 ||
 | 
			
		||||
				(int)gray  != 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Serializable */
 | 
			
		||||
	int serialSize() const;
 | 
			
		||||
	void serialize(char *buffer) const;
 | 
			
		||||
	static Tone *deserialize(const char *data, int len);
 | 
			
		||||
 | 
			
		||||
	/* Range (-255.0 ~ 255.0) */
 | 
			
		||||
	double red;
 | 
			
		||||
	double green;
 | 
			
		||||
	double blue;
 | 
			
		||||
	/* Range (0.0 ~ 255.0) */
 | 
			
		||||
	double gray;
 | 
			
		||||
 | 
			
		||||
	/* Normalized (-1.0 ~ 1.0) */
 | 
			
		||||
	Vec4 norm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Rect : public Serializable
 | 
			
		||||
{
 | 
			
		||||
	Rect()
 | 
			
		||||
	    : x(0), y(0), width(0), height(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	Rect(int x, int y, int width, int height);
 | 
			
		||||
	Rect(const Rect &o);
 | 
			
		||||
	Rect(const IntRect &r);
 | 
			
		||||
 | 
			
		||||
	bool operator==(const Rect &o) const;
 | 
			
		||||
	void operator=(const IntRect &rect);
 | 
			
		||||
	void set(int x, int y, int w, int h);
 | 
			
		||||
 | 
			
		||||
	FloatRect toFloatRect() const
 | 
			
		||||
	{
 | 
			
		||||
		return FloatRect(x, y, width, height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	IntRect toIntRect()
 | 
			
		||||
	{
 | 
			
		||||
		return IntRect(x, y, width, height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void empty();
 | 
			
		||||
 | 
			
		||||
	bool isEmpty() const
 | 
			
		||||
	{
 | 
			
		||||
		return !(x || y || width || height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR_INLINE(X,      int, x)
 | 
			
		||||
	DECL_ATTR_INLINE(Y,      int, y)
 | 
			
		||||
	DECL_ATTR_INLINE(Width,  int, width)
 | 
			
		||||
	DECL_ATTR_INLINE(Height, int, height)
 | 
			
		||||
 | 
			
		||||
	int serialSize() const;
 | 
			
		||||
	void serialize(char *buffer) const;
 | 
			
		||||
	static Rect *deserialize(const char *data, int len);
 | 
			
		||||
 | 
			
		||||
	int x;
 | 
			
		||||
	int y;
 | 
			
		||||
	int width;
 | 
			
		||||
	int height;
 | 
			
		||||
 | 
			
		||||
	sigc::signal<void> valueChanged;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* For internal use.
 | 
			
		||||
 * All drawable classes have properties of one or more of the above
 | 
			
		||||
 * types, which in an interpreted environment act as independent
 | 
			
		||||
 * objects, and rely on the GC to clean them up. When a drawable
 | 
			
		||||
 * class is constructed, these properties must have default objects
 | 
			
		||||
 * that are constructed with the class. C++ however has no GC, so
 | 
			
		||||
 * there is no way to clean them up when used directly with it.
 | 
			
		||||
 * Therefore the default objects are first created embedded in the
 | 
			
		||||
 * drawable class (so they get destroyed automatically from within
 | 
			
		||||
 * C++ if no pointers were changed), and the binding then takes
 | 
			
		||||
 * care of properly allocating new, independent objects and replacing
 | 
			
		||||
 * the defaults. Thus both C++ and the interpreted API can be used
 | 
			
		||||
 * without memory leakage.
 | 
			
		||||
 * This can be removed at a later point when no testing directly
 | 
			
		||||
 * from C++ is needed anymore. */
 | 
			
		||||
struct EtcTemps
 | 
			
		||||
{
 | 
			
		||||
	Color color;
 | 
			
		||||
	Tone tone;
 | 
			
		||||
	Rect rect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // ETC_H
 | 
			
		||||
							
								
								
									
										259
									
								
								src/eventthread.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								src/eventthread.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,259 @@
 | 
			
		|||
/*
 | 
			
		||||
** eventthread.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_events.h"
 | 
			
		||||
#include "SDL2/SDL_joystick.h"
 | 
			
		||||
#include "SDL2/SDL_messagebox.h"
 | 
			
		||||
#include "SDL2/SDL_timer.h"
 | 
			
		||||
#include "SDL2/SDL_thread.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
bool EventThread::keyStates[] = { false };
 | 
			
		||||
 | 
			
		||||
EventThread::JoyState EventThread::joyState =
 | 
			
		||||
{
 | 
			
		||||
     0, 0, { false }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
EventThread::MouseState EventThread::mouseState =
 | 
			
		||||
{
 | 
			
		||||
    0, 0, { false }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const Uint32 REQUEST_TERMINATION   = SDL_USEREVENT+0;
 | 
			
		||||
const Uint32 REQUEST_SETFULLSCREEN = SDL_USEREVENT+1;
 | 
			
		||||
const Uint32 REQUEST_WINRESIZE     = SDL_USEREVENT+2;
 | 
			
		||||
const Uint32 SHOW_MESSAGEBOX       = SDL_USEREVENT+3;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
EventThread::EventThread()
 | 
			
		||||
    : fullscreen(false)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
void EventThread::process(RGSSThreadData &rtData)
 | 
			
		||||
{
 | 
			
		||||
	SDL_Event event;
 | 
			
		||||
	SDL_Window *win = rtData.window;
 | 
			
		||||
	WindowSizeNotify &windowSizeMsg = rtData.windowSizeMsg;
 | 
			
		||||
 | 
			
		||||
	fullscreen = rtData.config.fullscreen;
 | 
			
		||||
 | 
			
		||||
	bool terminate = false;
 | 
			
		||||
 | 
			
		||||
	SDL_Joystick *js = 0;
 | 
			
		||||
	if (SDL_NumJoysticks() > 0)
 | 
			
		||||
		js = SDL_JoystickOpen(0);
 | 
			
		||||
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		if (!SDL_WaitEvent(&event))
 | 
			
		||||
		{
 | 
			
		||||
			qDebug() << "EventThread: Event error";
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		switch (event.type)
 | 
			
		||||
		{
 | 
			
		||||
		case SDL_WINDOWEVENT :
 | 
			
		||||
			switch (event.window.event)
 | 
			
		||||
			{
 | 
			
		||||
			case SDL_WINDOWEVENT_RESIZED :
 | 
			
		||||
				windowSizeMsg.notifyChange(event.window.data1,
 | 
			
		||||
				                           event.window.data2);
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SDL_WINDOWEVENT_CLOSE :
 | 
			
		||||
				terminate = true;
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			case SDL_WINDOWEVENT_FOCUS_LOST :
 | 
			
		||||
				resetInput();
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_QUIT :
 | 
			
		||||
		case REQUEST_TERMINATION :
 | 
			
		||||
			terminate = true;
 | 
			
		||||
			qDebug() << "EventThread termination requested";
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_KEYDOWN :
 | 
			
		||||
			if (event.key.keysym.scancode == SDL_SCANCODE_RETURN &&
 | 
			
		||||
			    (event.key.keysym.mod & KMOD_LALT))
 | 
			
		||||
			{
 | 
			
		||||
				setFullscreen(win, !fullscreen);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			keyStates[event.key.keysym.scancode] = true;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case REQUEST_SETFULLSCREEN :
 | 
			
		||||
			setFullscreen(win, static_cast<bool>(event.user.code));
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case REQUEST_WINRESIZE :
 | 
			
		||||
			SDL_SetWindowSize(win, event.window.data1, event.window.data2);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SHOW_MESSAGEBOX :
 | 
			
		||||
			SDL_ShowSimpleMessageBox(event.user.code,
 | 
			
		||||
			                         rtData.config.game.title.constData(),
 | 
			
		||||
			                         (const char*) event.user.data1, win);
 | 
			
		||||
			free(event.user.data1);
 | 
			
		||||
			msgBoxDone = true;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_KEYUP :
 | 
			
		||||
			keyStates[event.key.keysym.scancode] = false;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYBUTTONDOWN :
 | 
			
		||||
			joyState.buttons[event.jbutton.button] = true;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYBUTTONUP :
 | 
			
		||||
			joyState.buttons[event.jbutton.button] = false;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYAXISMOTION :
 | 
			
		||||
			if (event.jaxis.axis == 0)
 | 
			
		||||
				joyState.xAxis = event.jaxis.value;
 | 
			
		||||
			else
 | 
			
		||||
				joyState.yAxis = event.jaxis.value;
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYDEVICEADDED :
 | 
			
		||||
			if (event.jdevice.which > 0)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			js = SDL_JoystickOpen(0);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_JOYDEVICEREMOVED :
 | 
			
		||||
			resetInput();
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_MOUSEBUTTONDOWN :
 | 
			
		||||
			mouseState.buttons[event.button.button] = true;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_MOUSEBUTTONUP :
 | 
			
		||||
			mouseState.buttons[event.button.button] = false;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case SDL_MOUSEMOTION :
 | 
			
		||||
			mouseState.x = event.motion.x;
 | 
			
		||||
			mouseState.y = event.motion.y;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (terminate)
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (SDL_JoystickGetAttached(js))
 | 
			
		||||
		SDL_JoystickClose(js);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::cleanup()
 | 
			
		||||
{
 | 
			
		||||
	SDL_Event event;
 | 
			
		||||
	while (SDL_PollEvent(&event))
 | 
			
		||||
	{
 | 
			
		||||
		if (event.type == SHOW_MESSAGEBOX)
 | 
			
		||||
		{
 | 
			
		||||
			free(event.user.data1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::resetInput()
 | 
			
		||||
{
 | 
			
		||||
	memset(&keyStates, 0, sizeof(keyStates));
 | 
			
		||||
	memset(&joyState, 0, sizeof(joyState));
 | 
			
		||||
	memset(&mouseState.buttons, 0, sizeof(mouseState.buttons));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::setFullscreen(SDL_Window *win, bool mode)
 | 
			
		||||
{
 | 
			
		||||
	SDL_SetWindowFullscreen
 | 
			
		||||
	        (win, mode ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
 | 
			
		||||
	fullscreen = mode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::requestTerminate()
 | 
			
		||||
{
 | 
			
		||||
	SDL_Event event;
 | 
			
		||||
	event.type = REQUEST_TERMINATION;
 | 
			
		||||
	SDL_PushEvent(&event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::requestFullscreenMode(bool mode)
 | 
			
		||||
{
 | 
			
		||||
	if (mode == fullscreen)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	SDL_Event event;
 | 
			
		||||
	event.type = REQUEST_SETFULLSCREEN;
 | 
			
		||||
	event.user.code = static_cast<Sint32>(mode);
 | 
			
		||||
	SDL_PushEvent(&event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::requestWindowResize(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	SDL_Event event;
 | 
			
		||||
	event.type = REQUEST_WINRESIZE;
 | 
			
		||||
	event.window.data1 = width;
 | 
			
		||||
	event.window.data2 = height;
 | 
			
		||||
	SDL_PushEvent(&event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void EventThread::showMessageBox(const char *body, int flags)
 | 
			
		||||
{
 | 
			
		||||
	msgBoxDone = false;
 | 
			
		||||
 | 
			
		||||
	SDL_Event event;
 | 
			
		||||
	event.user.code = flags;
 | 
			
		||||
	event.user.data1 = strdup(body);
 | 
			
		||||
	event.type = SHOW_MESSAGEBOX;
 | 
			
		||||
	SDL_PushEvent(&event);
 | 
			
		||||
 | 
			
		||||
	/* Keep repainting screen while box is open */
 | 
			
		||||
	gState->graphics().repaintWait(&msgBoxDone);
 | 
			
		||||
	/* Prevent endless loops */
 | 
			
		||||
	resetInput();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool EventThread::getFullscreen()
 | 
			
		||||
{
 | 
			
		||||
	return fullscreen;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										169
									
								
								src/eventthread.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								src/eventthread.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,169 @@
 | 
			
		|||
/*
 | 
			
		||||
** eventthread.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef EVENTTHREAD_H
 | 
			
		||||
#define EVENTTHREAD_H
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_scancode.h"
 | 
			
		||||
#include "SDL2/SDL_joystick.h"
 | 
			
		||||
#include "SDL2/SDL_mouse.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_mutex.h"
 | 
			
		||||
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QVector>
 | 
			
		||||
 | 
			
		||||
struct RGSSThreadData;
 | 
			
		||||
struct SDL_Thread;
 | 
			
		||||
struct SDL_Window;
 | 
			
		||||
 | 
			
		||||
class EventThread
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	static bool keyStates[SDL_NUM_SCANCODES];
 | 
			
		||||
 | 
			
		||||
	struct JoyState
 | 
			
		||||
	{
 | 
			
		||||
		int xAxis;
 | 
			
		||||
		int yAxis;
 | 
			
		||||
 | 
			
		||||
		bool buttons[16];
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static JoyState joyState;
 | 
			
		||||
 | 
			
		||||
	struct MouseState
 | 
			
		||||
	{
 | 
			
		||||
		int x, y;
 | 
			
		||||
		bool buttons[SDL_BUTTON_X2+1];
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static MouseState mouseState;
 | 
			
		||||
 | 
			
		||||
	EventThread();
 | 
			
		||||
 | 
			
		||||
	void process(RGSSThreadData &rtData);
 | 
			
		||||
	void cleanup();
 | 
			
		||||
 | 
			
		||||
	/* Called from render thread */
 | 
			
		||||
	void requestFullscreenMode(bool mode);
 | 
			
		||||
	void requestWindowResize(int width, int height);
 | 
			
		||||
 | 
			
		||||
	void requestTerminate();
 | 
			
		||||
 | 
			
		||||
	bool getFullscreen();
 | 
			
		||||
 | 
			
		||||
	void showMessageBox(const char *body, int flags = 0);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void resetInput();
 | 
			
		||||
	void setFullscreen(SDL_Window *, bool mode);
 | 
			
		||||
	bool fullscreen;
 | 
			
		||||
	volatile bool msgBoxDone;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct WindowSizeNotify
 | 
			
		||||
{
 | 
			
		||||
	SDL_mutex *mutex;
 | 
			
		||||
 | 
			
		||||
	volatile bool changedFlag;
 | 
			
		||||
	volatile int w, h;
 | 
			
		||||
 | 
			
		||||
	WindowSizeNotify()
 | 
			
		||||
	{
 | 
			
		||||
		mutex = SDL_CreateMutex();
 | 
			
		||||
		changedFlag = false;
 | 
			
		||||
		w = h = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~WindowSizeNotify()
 | 
			
		||||
	{
 | 
			
		||||
		SDL_DestroyMutex(mutex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Done from the sending side */
 | 
			
		||||
	void notifyChange(int w, int h)
 | 
			
		||||
	{
 | 
			
		||||
		SDL_LockMutex(mutex);
 | 
			
		||||
 | 
			
		||||
		this->w = w;
 | 
			
		||||
		this->h = h;
 | 
			
		||||
		changedFlag = true;
 | 
			
		||||
 | 
			
		||||
		SDL_UnlockMutex(mutex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Done from the receiving side */
 | 
			
		||||
	bool pollChange(int *w, int *h)
 | 
			
		||||
	{
 | 
			
		||||
		if (!changedFlag)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		SDL_LockMutex(mutex);
 | 
			
		||||
 | 
			
		||||
		*w = this->w;
 | 
			
		||||
		*h = this->h;
 | 
			
		||||
		changedFlag = false;
 | 
			
		||||
 | 
			
		||||
		SDL_UnlockMutex(mutex);
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct RGSSThreadData
 | 
			
		||||
{
 | 
			
		||||
	/* Main thread sets this to request render thread to terminate */
 | 
			
		||||
	volatile bool rqTerm;
 | 
			
		||||
	/* In response, render thread sets this to confirm
 | 
			
		||||
	 * that it received the request and isn't stuck */
 | 
			
		||||
	volatile bool rqTermAck;
 | 
			
		||||
 | 
			
		||||
	EventThread *ethread;
 | 
			
		||||
	WindowSizeNotify windowSizeMsg;
 | 
			
		||||
 | 
			
		||||
	const char *argv0;
 | 
			
		||||
 | 
			
		||||
	SDL_Window *window;
 | 
			
		||||
 | 
			
		||||
	Vec2 sizeResoRatio;
 | 
			
		||||
 | 
			
		||||
	Config config;
 | 
			
		||||
 | 
			
		||||
	QByteArray rgssErrorMsg;
 | 
			
		||||
 | 
			
		||||
	RGSSThreadData(EventThread *ethread,
 | 
			
		||||
	                 const char *argv0,
 | 
			
		||||
	                 SDL_Window *window)
 | 
			
		||||
	    : rqTerm(false),
 | 
			
		||||
	      rqTermAck(false),
 | 
			
		||||
	      ethread(ethread),
 | 
			
		||||
	      argv0(argv0),
 | 
			
		||||
	      window(window),
 | 
			
		||||
	      sizeResoRatio(1, 1)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // EVENTTHREAD_H
 | 
			
		||||
							
								
								
									
										63
									
								
								src/exception.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/exception.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
/*
 | 
			
		||||
** exception.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef EXCEPTION_H
 | 
			
		||||
#define EXCEPTION_H
 | 
			
		||||
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
struct Exception
 | 
			
		||||
{
 | 
			
		||||
	enum Type
 | 
			
		||||
	{
 | 
			
		||||
		RGSSError,
 | 
			
		||||
		NoFileError,
 | 
			
		||||
		IOError,
 | 
			
		||||
 | 
			
		||||
		/* Already defined by ruby */
 | 
			
		||||
		TypeError,
 | 
			
		||||
		ArgumentError,
 | 
			
		||||
 | 
			
		||||
		/* New types introduced in mkxp */
 | 
			
		||||
		PHYSFSError,
 | 
			
		||||
		SDLError,
 | 
			
		||||
		MKXPError
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Type type;
 | 
			
		||||
	QByteArray fmt;
 | 
			
		||||
	QByteArray arg1;
 | 
			
		||||
	QByteArray arg2;
 | 
			
		||||
 | 
			
		||||
	Exception(Type type, QByteArray fmt,
 | 
			
		||||
	          QByteArray arg1 = QByteArray(),
 | 
			
		||||
	          QByteArray arg2 = QByteArray())
 | 
			
		||||
	    : type(type), fmt(fmt), arg1(arg1), arg2(arg2)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void snprintf(char *buffer, size_t bufSize) const
 | 
			
		||||
	{
 | 
			
		||||
		::snprintf(buffer, bufSize, fmt.constData(), arg1.constData(), arg2.constData());
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // EXCEPTION_H
 | 
			
		||||
							
								
								
									
										735
									
								
								src/filesystem.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										735
									
								
								src/filesystem.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,735 @@
 | 
			
		|||
/*
 | 
			
		||||
** filesystem.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "filesystem.h"
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include "physfs.h"
 | 
			
		||||
 | 
			
		||||
#include <QHash>
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
 | 
			
		||||
#include "stdio.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
struct RGSS_entryData
 | 
			
		||||
{
 | 
			
		||||
	qint64 offset;
 | 
			
		||||
	quint64 size;
 | 
			
		||||
	quint32 startMagic;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct RGSS_entryHandle
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryData data;
 | 
			
		||||
	quint32 currentMagic;
 | 
			
		||||
	quint64 currentOffset;
 | 
			
		||||
	PHYSFS_Io *io;
 | 
			
		||||
 | 
			
		||||
	RGSS_entryHandle(const RGSS_entryData &data)
 | 
			
		||||
	    : data(data),
 | 
			
		||||
	      currentMagic(data.startMagic),
 | 
			
		||||
	      currentOffset(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	RGSS_entryHandle(const RGSS_entryHandle &other)
 | 
			
		||||
	    : data(other.data),
 | 
			
		||||
	      currentMagic(other.currentMagic),
 | 
			
		||||
	      currentOffset(other.currentOffset)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef QList<QByteArray> QByteList;
 | 
			
		||||
 | 
			
		||||
struct RGSS_archiveData
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_Io *archiveIo;
 | 
			
		||||
	QHash<QByteArray, RGSS_entryData> entryHash;
 | 
			
		||||
	QHash<QByteArray, bool> dirHash;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
readUint32(PHYSFS_Io *io, quint32 &result)
 | 
			
		||||
{
 | 
			
		||||
	char buff[4];
 | 
			
		||||
	PHYSFS_sint64 count = io->read(io, buff, 4);
 | 
			
		||||
 | 
			
		||||
	result = ((buff[0] << 0x00) & 0x000000FF) |
 | 
			
		||||
	         ((buff[1] << 0x08) & 0x0000FF00) |
 | 
			
		||||
	         ((buff[2] << 0x10) & 0x00FF0000) |
 | 
			
		||||
	         ((buff[3] << 0x18) & 0xFF000000) ;
 | 
			
		||||
 | 
			
		||||
	return (count == 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define RGSS_HEADER_1 0x53534752
 | 
			
		||||
#define RGSS_HEADER_2 0x1004441
 | 
			
		||||
 | 
			
		||||
#define RGSS_MAGIC 0xDEADCAFE
 | 
			
		||||
 | 
			
		||||
#define PHYSFS_ALLOC(type) \
 | 
			
		||||
	static_cast<type*>(PHYSFS_getAllocator()->Malloc(sizeof(type)))
 | 
			
		||||
 | 
			
		||||
static inline quint32
 | 
			
		||||
advanceMagic(quint32 &magic)
 | 
			
		||||
{
 | 
			
		||||
	quint32 old = magic;
 | 
			
		||||
 | 
			
		||||
	magic = magic * 7 + 3;
 | 
			
		||||
 | 
			
		||||
	return old;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct MagicState
 | 
			
		||||
{
 | 
			
		||||
	quint32 magic;
 | 
			
		||||
	quint64 offset;
 | 
			
		||||
 | 
			
		||||
	MagicState(quint64 offset = 0)
 | 
			
		||||
	    : offset(offset)
 | 
			
		||||
	{
 | 
			
		||||
		magic = RGSS_MAGIC;
 | 
			
		||||
 | 
			
		||||
		for (uint i = 0; i < (offset/4); ++i)
 | 
			
		||||
			advanceBlock();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quint8 advancePath()
 | 
			
		||||
	{
 | 
			
		||||
		quint8 ret = magic & 0xFF;
 | 
			
		||||
 | 
			
		||||
		offset++;
 | 
			
		||||
		advanceBlock();
 | 
			
		||||
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	quint8 advanceData()
 | 
			
		||||
	{
 | 
			
		||||
		quint8 ret = magic & 0xFF;
 | 
			
		||||
 | 
			
		||||
		if (offset++ % 4 == 0)
 | 
			
		||||
			advanceBlock();
 | 
			
		||||
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void advanceBlock()
 | 
			
		||||
	{
 | 
			
		||||
		magic = magic * 7 + 3;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static PHYSFS_sint64
 | 
			
		||||
RGSS_ioRead(PHYSFS_Io *self, void *buffer, PHYSFS_uint64 len)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	quint64 toRead = qMin(entry->data.size - entry->currentOffset, len);
 | 
			
		||||
	quint64 offs = entry->currentOffset;
 | 
			
		||||
 | 
			
		||||
	entry->io->seek(entry->io, entry->data.offset + offs);
 | 
			
		||||
 | 
			
		||||
	quint64 buffI = 0;
 | 
			
		||||
	for (quint64 o = offs; o < offs + toRead;)
 | 
			
		||||
	{
 | 
			
		||||
		quint8 bitOffset = (0x8 * (o % 4));
 | 
			
		||||
		quint8 magicByte = (entry->currentMagic >> bitOffset) & 0xFF;
 | 
			
		||||
 | 
			
		||||
		quint8 byte;
 | 
			
		||||
		entry->io->read(entry->io, &byte, 1);
 | 
			
		||||
 | 
			
		||||
		((quint8*) buffer)[buffI++] = byte ^ magicByte;
 | 
			
		||||
 | 
			
		||||
		if (++o % 4 == 0)
 | 
			
		||||
			advanceMagic(entry->currentMagic);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	entry->currentOffset += toRead;
 | 
			
		||||
 | 
			
		||||
	return toRead;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
RGSS_ioSeek(PHYSFS_Io *self, PHYSFS_uint64 offset)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	if (offset == entry->currentOffset)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (offset > entry->data.size-1)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* If rewinding, we need to rewind to begining */
 | 
			
		||||
	if (offset < entry->currentOffset)
 | 
			
		||||
	{
 | 
			
		||||
		entry->currentOffset = 0;
 | 
			
		||||
		entry->currentMagic = entry->data.startMagic;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* For each 4 bytes sought, advance magic */
 | 
			
		||||
	quint64 dwordsSought = (offset - entry->currentOffset) / 4;
 | 
			
		||||
	for (quint64 i = 0; i < dwordsSought; ++i)
 | 
			
		||||
		advanceMagic(entry->currentMagic);
 | 
			
		||||
 | 
			
		||||
	entry->currentOffset = offset;
 | 
			
		||||
	entry->io->seek(entry->io, entry->data.offset + entry->currentOffset);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PHYSFS_sint64
 | 
			
		||||
RGSS_ioTell(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	return entry->currentOffset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PHYSFS_sint64
 | 
			
		||||
RGSS_ioLength(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	return entry->data.size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PHYSFS_Io*
 | 
			
		||||
RGSS_ioDuplicate(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
	RGSS_entryHandle *entryDup = new RGSS_entryHandle(*entry);
 | 
			
		||||
 | 
			
		||||
	PHYSFS_Io *dup = PHYSFS_ALLOC(PHYSFS_Io);
 | 
			
		||||
	*dup = *self;
 | 
			
		||||
	dup->opaque = entryDup;
 | 
			
		||||
 | 
			
		||||
	return dup;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
RGSS_ioDestroy(PHYSFS_Io *self)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_entryHandle *entry = static_cast<RGSS_entryHandle*>(self->opaque);
 | 
			
		||||
 | 
			
		||||
	delete entry;
 | 
			
		||||
 | 
			
		||||
	PHYSFS_getAllocator()->Free(self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const PHYSFS_Io RGSS_IoTemplate =
 | 
			
		||||
{
 | 
			
		||||
    0, /* version */
 | 
			
		||||
    0, /* opaque */
 | 
			
		||||
    RGSS_ioRead,
 | 
			
		||||
    0, /* write */
 | 
			
		||||
    RGSS_ioSeek,
 | 
			
		||||
    RGSS_ioTell,
 | 
			
		||||
    RGSS_ioLength,
 | 
			
		||||
    RGSS_ioDuplicate,
 | 
			
		||||
    0, /* flush */
 | 
			
		||||
    RGSS_ioDestroy
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void*
 | 
			
		||||
RGSS_openArchive(PHYSFS_Io *io, const char *, int forWrite)
 | 
			
		||||
{
 | 
			
		||||
	if (forWrite)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* Check header */
 | 
			
		||||
	quint32 header1, header2;
 | 
			
		||||
	readUint32(io, header1);
 | 
			
		||||
	readUint32(io, header2);
 | 
			
		||||
 | 
			
		||||
	if (header1 != RGSS_HEADER_1 || header2 != RGSS_HEADER_2)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	RGSS_archiveData *data = new RGSS_archiveData;
 | 
			
		||||
	data->archiveIo = io;
 | 
			
		||||
 | 
			
		||||
	quint32 magic = RGSS_MAGIC;
 | 
			
		||||
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		/* Read filename length,
 | 
			
		||||
         * if nothing was read, no files remain */
 | 
			
		||||
		quint32 nameLen;
 | 
			
		||||
		if (!readUint32(io, nameLen))
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		nameLen ^= advanceMagic(magic);
 | 
			
		||||
 | 
			
		||||
		static char nameBuf[512];
 | 
			
		||||
		uint i;
 | 
			
		||||
		for (i = 0; i < nameLen; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			char c;
 | 
			
		||||
			io->read(io, &c, 1);
 | 
			
		||||
			nameBuf[i] = c ^ (advanceMagic(magic) & 0xFF);
 | 
			
		||||
			if (nameBuf[i] == '\\')
 | 
			
		||||
				nameBuf[i] = '/';
 | 
			
		||||
		}
 | 
			
		||||
		nameBuf[i] = 0;
 | 
			
		||||
 | 
			
		||||
		quint32 entrySize;
 | 
			
		||||
		readUint32(io, entrySize);
 | 
			
		||||
		entrySize ^= advanceMagic(magic);
 | 
			
		||||
 | 
			
		||||
		RGSS_entryData entry;
 | 
			
		||||
		entry.offset = io->tell(io);
 | 
			
		||||
		entry.size = entrySize;
 | 
			
		||||
		entry.startMagic = magic;
 | 
			
		||||
 | 
			
		||||
		data->entryHash.insert(nameBuf, entry);
 | 
			
		||||
 | 
			
		||||
		/* Test for new folder */
 | 
			
		||||
		for (i = nameLen; i > 0; i--)
 | 
			
		||||
			if (nameBuf[i] == '/')
 | 
			
		||||
			{
 | 
			
		||||
				nameBuf[i] = '\0';
 | 
			
		||||
				if (!data->dirHash.contains(nameBuf))
 | 
			
		||||
					data->dirHash.insert(nameBuf, true);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		io->seek(io, entry.offset + entry.size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
RGSS_enumerateFiles(void *opaque, const char *dirname,
 | 
			
		||||
                    PHYSFS_EnumFilesCallback cb,
 | 
			
		||||
                    const char *origdir, void *callbackdata)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
 | 
			
		||||
 | 
			
		||||
	QString dirn(dirname);
 | 
			
		||||
 | 
			
		||||
	char dirBuf[512];
 | 
			
		||||
	char baseBuf[512];
 | 
			
		||||
	QByteList keys = data->entryHash.keys();
 | 
			
		||||
	keys += data->dirHash.keys();
 | 
			
		||||
 | 
			
		||||
	Q_FOREACH (const QByteArray &filename, keys)
 | 
			
		||||
	{
 | 
			
		||||
		/* Get the filename directory part */
 | 
			
		||||
		strcpy(dirBuf, filename.constData());
 | 
			
		||||
		strcpy(baseBuf, filename.constData());
 | 
			
		||||
 | 
			
		||||
		/* Extract path and basename */
 | 
			
		||||
		const char *dirpath = "";
 | 
			
		||||
		char *basename = dirBuf;
 | 
			
		||||
 | 
			
		||||
		for (int i = filename.size(); i >= 0; i--)
 | 
			
		||||
			if (dirBuf[i] == '/')
 | 
			
		||||
			{
 | 
			
		||||
				dirBuf[i] = '\0';
 | 
			
		||||
				dirpath = dirBuf;
 | 
			
		||||
 | 
			
		||||
				basename = &dirBuf[i+1];
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		/* Compare to provided dirname */
 | 
			
		||||
		if (strcmp(dirpath, dirname) == 0)
 | 
			
		||||
			cb(callbackdata, origdir, basename);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PHYSFS_Io*
 | 
			
		||||
RGSS_openRead(void *opaque, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
 | 
			
		||||
 | 
			
		||||
	if (!data->entryHash.contains(filename))
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	RGSS_entryHandle *entry = new RGSS_entryHandle(data->entryHash[filename]);
 | 
			
		||||
	entry->io = data->archiveIo->duplicate(data->archiveIo);
 | 
			
		||||
 | 
			
		||||
	PHYSFS_Io *io = PHYSFS_ALLOC(PHYSFS_Io);
 | 
			
		||||
 | 
			
		||||
	*io = RGSS_IoTemplate;
 | 
			
		||||
	io->opaque = entry;
 | 
			
		||||
 | 
			
		||||
	return io;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
RGSS_stat(void *opaque, const char *filename, PHYSFS_Stat *stat)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
 | 
			
		||||
 | 
			
		||||
	bool hasFile = data->entryHash.contains(filename);
 | 
			
		||||
	bool hasDir  = data->dirHash.contains(filename);
 | 
			
		||||
 | 
			
		||||
	if (!hasFile && !hasDir)
 | 
			
		||||
	{
 | 
			
		||||
		PHYSFS_setErrorCode(PHYSFS_ERR_NOT_FOUND);
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stat->modtime    =
 | 
			
		||||
	stat->createtime =
 | 
			
		||||
	stat->accesstime = 0;
 | 
			
		||||
	stat->readonly   = 1;
 | 
			
		||||
 | 
			
		||||
	if (hasFile)
 | 
			
		||||
	{
 | 
			
		||||
		RGSS_entryData &entry = data->entryHash[filename];
 | 
			
		||||
 | 
			
		||||
		stat->filesize = entry.size;
 | 
			
		||||
		stat->filetype = PHYSFS_FILETYPE_REGULAR;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		stat->filesize = 0;
 | 
			
		||||
		stat->filetype = PHYSFS_FILETYPE_DIRECTORY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
RGSS_closeArchive(void *opaque)
 | 
			
		||||
{
 | 
			
		||||
	RGSS_archiveData *data = static_cast<RGSS_archiveData*>(opaque);
 | 
			
		||||
 | 
			
		||||
	delete data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PHYSFS_Io*
 | 
			
		||||
RGSS_noop1(void*, const char*)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
RGSS_noop2(void*, const char*)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const PHYSFS_Archiver RGSS_Archiver =
 | 
			
		||||
{
 | 
			
		||||
	0,
 | 
			
		||||
    {
 | 
			
		||||
        "RGSSAD",
 | 
			
		||||
        "RGSS encrypted archive format",
 | 
			
		||||
        "Jonas Kulla <Nyocurio@gmail.com>",
 | 
			
		||||
        "http://k-du.de/rgss/rgss.html",
 | 
			
		||||
        0 /* symlinks not supported */
 | 
			
		||||
    },
 | 
			
		||||
    RGSS_openArchive,
 | 
			
		||||
    RGSS_enumerateFiles,
 | 
			
		||||
    RGSS_openRead,
 | 
			
		||||
    RGSS_noop1, /* openWrite */
 | 
			
		||||
    RGSS_noop1, /* openAppend */
 | 
			
		||||
    RGSS_noop2, /* remove */
 | 
			
		||||
    RGSS_noop2, /* mkdir */
 | 
			
		||||
    RGSS_stat,
 | 
			
		||||
    RGSS_closeArchive
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FileStream::FileStream(PHYSFS_File *file)
 | 
			
		||||
{
 | 
			
		||||
	p = file;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileStream::~FileStream()
 | 
			
		||||
{
 | 
			
		||||
//	if (p)
 | 
			
		||||
//		PHYSFS_close(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileStream::operator=(const FileStream &o)
 | 
			
		||||
{
 | 
			
		||||
	p = o.p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sf::Int64 FileStream::read(void *data, sf::Int64 size)
 | 
			
		||||
{
 | 
			
		||||
	if (!p)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return PHYSFS_readBytes(p, data, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sf::Int64 FileStream::seek(sf::Int64 position)
 | 
			
		||||
{
 | 
			
		||||
	if (!p)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	int success = PHYSFS_seek(p, (PHYSFS_uint64) position);
 | 
			
		||||
 | 
			
		||||
	return success ? position : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sf::Int64 FileStream::tell()
 | 
			
		||||
{
 | 
			
		||||
	if (!p)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return PHYSFS_tell(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sf::Int64 FileStream::getSize()
 | 
			
		||||
{
 | 
			
		||||
	if (!p)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return PHYSFS_fileLength(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sf::Int64 FileStream::write(const void *data, sf::Int64 size)
 | 
			
		||||
{
 | 
			
		||||
	if (!p)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return PHYSFS_writeBytes(p, data, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileStream::close()
 | 
			
		||||
{
 | 
			
		||||
	if (p)
 | 
			
		||||
	{
 | 
			
		||||
		PHYSFS_close(p);
 | 
			
		||||
		p = 0;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void enumCB(void *, const char *origdir,
 | 
			
		||||
                   const char *fname)
 | 
			
		||||
{
 | 
			
		||||
	qDebug() << origdir << fname;
 | 
			
		||||
	char buf[128];
 | 
			
		||||
	sprintf(buf, "%s/%s", origdir, fname);
 | 
			
		||||
	PHYSFS_enumerateFilesCallback(buf, enumCB, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileSystem::FileSystem(const char *argv0)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_init(argv0);
 | 
			
		||||
	PHYSFS_registerArchiver(&RGSS_Archiver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileSystem::~FileSystem()
 | 
			
		||||
{
 | 
			
		||||
	if (PHYSFS_deinit() == 0)
 | 
			
		||||
		qDebug() << "PhyFS failed to deinit.";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FileSystem::addPath(const char *path)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_mount(path, 0, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *imgExt[] =
 | 
			
		||||
{
 | 
			
		||||
	"jpg",
 | 
			
		||||
	"png"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *audExt[] =
 | 
			
		||||
{
 | 
			
		||||
//	"mid",
 | 
			
		||||
//	"midi",
 | 
			
		||||
	"mp3",
 | 
			
		||||
	"ogg",
 | 
			
		||||
	"wav",
 | 
			
		||||
	"wma"  // FIXME this prolly isn't even supported lol
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *fonExt[] =
 | 
			
		||||
{
 | 
			
		||||
    "ttf"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FileExtensions
 | 
			
		||||
{
 | 
			
		||||
	const char **ext;
 | 
			
		||||
	int count;
 | 
			
		||||
} fileExtensions[] =
 | 
			
		||||
{
 | 
			
		||||
	{ imgExt, ARRAY_SIZE(imgExt) },
 | 
			
		||||
	{ audExt, ARRAY_SIZE(audExt) },
 | 
			
		||||
	{ fonExt, ARRAY_SIZE(fonExt) }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *completeFileName(const char *filename,
 | 
			
		||||
                                    FileSystem::FileType type)
 | 
			
		||||
{
 | 
			
		||||
	static char buff[1024];
 | 
			
		||||
 | 
			
		||||
	if (PHYSFS_exists(filename))
 | 
			
		||||
		return filename;
 | 
			
		||||
 | 
			
		||||
	if (type != FileSystem::Undefined)
 | 
			
		||||
	{
 | 
			
		||||
		FileExtensions *extTest = &fileExtensions[type];
 | 
			
		||||
		for (int i = 0; i < extTest->count; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			snprintf(buff, sizeof(buff), "%s.%s", filename, extTest->ext[i]);
 | 
			
		||||
			if (PHYSFS_exists(buff))
 | 
			
		||||
				return buff;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static PHYSFS_File *openReadInt(const char *filename,
 | 
			
		||||
                                FileSystem::FileType type)
 | 
			
		||||
{
 | 
			
		||||
	const char *foundName = completeFileName(filename, type);
 | 
			
		||||
 | 
			
		||||
	if (!foundName)
 | 
			
		||||
		throw Exception(Exception::NoFileError,
 | 
			
		||||
	                "No such file or directory - %s", filename);
 | 
			
		||||
 | 
			
		||||
	PHYSFS_File *handle = PHYSFS_openRead(foundName);
 | 
			
		||||
	if (!handle)
 | 
			
		||||
		throw Exception(Exception::PHYSFSError, "PhysFS: %s", PHYSFS_getLastError());
 | 
			
		||||
 | 
			
		||||
	PHYSFS_fileLength(handle);
 | 
			
		||||
 | 
			
		||||
	return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FileStream FileSystem::openRead(const char *filename,
 | 
			
		||||
                                FileType type)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *handle = openReadInt(filename, type);
 | 
			
		||||
 | 
			
		||||
	return FileStream(handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline PHYSFS_File *sdlPHYS(SDL_RWops *ops)
 | 
			
		||||
{
 | 
			
		||||
	return static_cast<PHYSFS_File*>(ops->hidden.unknown.data1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Sint64 SDL_RWopsSize(SDL_RWops *ops)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *f = sdlPHYS(ops);
 | 
			
		||||
 | 
			
		||||
	if (!f)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	return PHYSFS_fileLength(f);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Sint64 SDL_RWopsSeek(SDL_RWops *ops, Sint64 offset, int whence)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *f = sdlPHYS(ops);
 | 
			
		||||
 | 
			
		||||
	if (!f)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	Sint64 base;
 | 
			
		||||
	switch (whence)
 | 
			
		||||
	{
 | 
			
		||||
	default:
 | 
			
		||||
	case RW_SEEK_SET :
 | 
			
		||||
		base = 0;
 | 
			
		||||
		break;
 | 
			
		||||
	case RW_SEEK_CUR :
 | 
			
		||||
		base = PHYSFS_tell(f);
 | 
			
		||||
		break;
 | 
			
		||||
	case RW_SEEK_END :
 | 
			
		||||
		base = PHYSFS_fileLength(f);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int result = PHYSFS_seek(f, base + offset);
 | 
			
		||||
 | 
			
		||||
	return (result != 0) ? PHYSFS_tell(f) : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t SDL_RWopsRead(SDL_RWops *ops, void *buffer, size_t size, size_t maxnum)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *f = sdlPHYS(ops);
 | 
			
		||||
 | 
			
		||||
	if (!f)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	PHYSFS_sint64 result = PHYSFS_readBytes(f, buffer, size*maxnum);
 | 
			
		||||
 | 
			
		||||
	return (result != -1) ? (result / size) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static size_t SDL_RWopsWrite(SDL_RWops *ops, const void *buffer, size_t size, size_t num)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *f = sdlPHYS(ops);
 | 
			
		||||
 | 
			
		||||
	if (!f)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	PHYSFS_sint64 result = PHYSFS_writeBytes(f, buffer, size*num);
 | 
			
		||||
 | 
			
		||||
	return (result != -1) ? (result / size) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int SDL_RWopsClose(SDL_RWops *ops)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *f = sdlPHYS(ops);
 | 
			
		||||
 | 
			
		||||
	if (!f)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	int result = PHYSFS_close(f);
 | 
			
		||||
 | 
			
		||||
	return (result != 0) ? 0 : -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Uint32 SDL_RWOPS_PHYSFS = SDL_RWOPS_UNKNOWN+10;
 | 
			
		||||
 | 
			
		||||
void FileSystem::openRead(SDL_RWops &ops,
 | 
			
		||||
                          const char *filename,
 | 
			
		||||
                          FileType type)
 | 
			
		||||
{
 | 
			
		||||
	PHYSFS_File *handle = openReadInt(filename, type);
 | 
			
		||||
 | 
			
		||||
	ops.size  = SDL_RWopsSize;
 | 
			
		||||
	ops.seek  = SDL_RWopsSeek;
 | 
			
		||||
	ops.read  = SDL_RWopsRead;
 | 
			
		||||
	ops.write = SDL_RWopsWrite;
 | 
			
		||||
	ops.close = SDL_RWopsClose;
 | 
			
		||||
 | 
			
		||||
	ops.type = SDL_RWOPS_PHYSFS;
 | 
			
		||||
	ops.hidden.unknown.data1 = handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileSystem::exists(const char *filename, FileType type)
 | 
			
		||||
{
 | 
			
		||||
	const char *foundName = completeFileName(filename, type);
 | 
			
		||||
 | 
			
		||||
	return (foundName != 0);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								src/filesystem.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/filesystem.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
/*
 | 
			
		||||
** filesystem.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef FILESYSTEM_H
 | 
			
		||||
#define FILESYSTEM_H
 | 
			
		||||
 | 
			
		||||
#include "SFML/System/InputStream.hpp"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_rwops.h"
 | 
			
		||||
 | 
			
		||||
struct PHYSFS_File;
 | 
			
		||||
 | 
			
		||||
class FileStream : public sf::InputStream
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	FileStream(PHYSFS_File *);
 | 
			
		||||
	~FileStream();
 | 
			
		||||
 | 
			
		||||
	void operator=(const FileStream &o);
 | 
			
		||||
 | 
			
		||||
	sf::Int64 read(void *data, sf::Int64 size);
 | 
			
		||||
	sf::Int64 seek(sf::Int64 position);
 | 
			
		||||
	sf::Int64 tell();
 | 
			
		||||
	sf::Int64 getSize();
 | 
			
		||||
 | 
			
		||||
	sf::Int64 write(const void *data, sf::Int64 size);
 | 
			
		||||
 | 
			
		||||
	void close();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	PHYSFS_File *p; /* NULL denotes invalid stream */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FileSystem
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	FileSystem(const char *argv0);
 | 
			
		||||
	~FileSystem();
 | 
			
		||||
 | 
			
		||||
	void addPath(const char *path);
 | 
			
		||||
 | 
			
		||||
	/* For extension supplementing */
 | 
			
		||||
	enum FileType
 | 
			
		||||
	{
 | 
			
		||||
		Image = 0,
 | 
			
		||||
		Audio,
 | 
			
		||||
		Font,
 | 
			
		||||
		Undefined
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	FileStream openRead(const char *filename,
 | 
			
		||||
	                    FileType type = Undefined);
 | 
			
		||||
 | 
			
		||||
	void openRead(SDL_RWops &ops,
 | 
			
		||||
	              const char *filename,
 | 
			
		||||
	              FileType type = Undefined);
 | 
			
		||||
 | 
			
		||||
	bool exists(const char *filename,
 | 
			
		||||
	            FileType type = Undefined);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern const Uint32 SDL_RWOPS_PHYSFS;
 | 
			
		||||
 | 
			
		||||
#endif // FILESYSTEM_H
 | 
			
		||||
							
								
								
									
										92
									
								
								src/flashable.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/flashable.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
/*
 | 
			
		||||
** flashable.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef FLASHABLE_H
 | 
			
		||||
#define FLASHABLE_H
 | 
			
		||||
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
class Flashable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Flashable()
 | 
			
		||||
	    : flashColor(0, 0, 0, 0),
 | 
			
		||||
	      flashing(false),
 | 
			
		||||
	      emptyFlashFlag(false)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	virtual ~Flashable() {}
 | 
			
		||||
 | 
			
		||||
	void flash(const Vec4 *color, int duration)
 | 
			
		||||
	{
 | 
			
		||||
		if (duration < 1)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		flashing = true;
 | 
			
		||||
		this->duration = duration;
 | 
			
		||||
		counter = 0;
 | 
			
		||||
 | 
			
		||||
		if (!color)
 | 
			
		||||
		{
 | 
			
		||||
			emptyFlashFlag = true;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		flashColor = *color;
 | 
			
		||||
		flashAlpha = flashColor.w;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void update()
 | 
			
		||||
	{
 | 
			
		||||
		if (!flashing)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (++counter > duration)
 | 
			
		||||
		{
 | 
			
		||||
			/* Flash finished. Cleanup */
 | 
			
		||||
			flashColor = Vec4(0, 0, 0, 0);
 | 
			
		||||
			flashing = false;
 | 
			
		||||
			emptyFlashFlag = false;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* No need to update flash color on empty flash */
 | 
			
		||||
		if (emptyFlashFlag)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		float prog = (float) counter / duration;
 | 
			
		||||
		flashColor.w = flashAlpha * (1 - prog);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	Vec4 flashColor;
 | 
			
		||||
	bool flashing;
 | 
			
		||||
	bool emptyFlashFlag;
 | 
			
		||||
private:
 | 
			
		||||
	float flashAlpha;
 | 
			
		||||
	int duration;
 | 
			
		||||
	int counter;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // FLASHABLE_H
 | 
			
		||||
							
								
								
									
										240
									
								
								src/font.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								src/font.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,240 @@
 | 
			
		|||
/*
 | 
			
		||||
** font.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "font.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "filesystem.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include "../assets/liberation.ttf.xxd"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_ttf.h"
 | 
			
		||||
 | 
			
		||||
#include <QHash>
 | 
			
		||||
#include <QByteArray>
 | 
			
		||||
#include <QPair>
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
#define BUNDLED_FONT liberation
 | 
			
		||||
 | 
			
		||||
#define BUNDLED_FONT_D(f) assets_## f ##_ttf
 | 
			
		||||
#define BUNDLED_FONT_L(f) assets_## f ##_ttf_len
 | 
			
		||||
 | 
			
		||||
// Go fuck yourself CPP
 | 
			
		||||
#define BNDL_F_D(f) BUNDLED_FONT_D(f)
 | 
			
		||||
#define BNDL_F_L(f) BUNDLED_FONT_L(f)
 | 
			
		||||
 | 
			
		||||
typedef QPair<QByteArray, int> FontKey;
 | 
			
		||||
 | 
			
		||||
struct FontPoolPrivate
 | 
			
		||||
{
 | 
			
		||||
	QHash<FontKey, TTF_Font*> hash;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FontPool::FontPool()
 | 
			
		||||
{
 | 
			
		||||
	p = new FontPoolPrivate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FontPool::~FontPool()
 | 
			
		||||
{
 | 
			
		||||
	QHash<FontKey, TTF_Font*>::const_iterator iter;
 | 
			
		||||
	for (iter = p->hash.begin(); iter != p->hash.end(); ++iter)
 | 
			
		||||
		TTF_CloseFont(iter.value());
 | 
			
		||||
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SDL_RWops *openBundledFont()
 | 
			
		||||
{
 | 
			
		||||
	return SDL_RWFromConstMem(BNDL_F_D(BUNDLED_FONT), BNDL_F_L(BUNDLED_FONT));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_TTF_Font *FontPool::request(const char *filename,
 | 
			
		||||
                            int size)
 | 
			
		||||
{
 | 
			
		||||
	// FIXME Find out how font path resolution is done in VX/Ace
 | 
			
		||||
	QByteArray nameKey = QByteArray(filename).toLower();
 | 
			
		||||
	nameKey.replace(' ', '_');
 | 
			
		||||
 | 
			
		||||
	bool useBundled = false;
 | 
			
		||||
	QByteArray path = QByteArray("Fonts/") + nameKey;
 | 
			
		||||
	if (!gState->fileSystem().exists(path.constData(), FileSystem::Font))
 | 
			
		||||
	{
 | 
			
		||||
		useBundled = true;
 | 
			
		||||
		nameKey = " bundled";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FontKey key(nameKey, size);
 | 
			
		||||
 | 
			
		||||
	TTF_Font *font = p->hash.value(key, 0);
 | 
			
		||||
 | 
			
		||||
	if (font)
 | 
			
		||||
	{
 | 
			
		||||
//		static int i=0;qDebug() << "FontPool: <?+>" << i++;
 | 
			
		||||
		return font;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
//	qDebug() << "FontPool: <?->";
 | 
			
		||||
 | 
			
		||||
	/* Not in hash, create */
 | 
			
		||||
	SDL_RWops *ops;
 | 
			
		||||
 | 
			
		||||
	if (useBundled)
 | 
			
		||||
	{
 | 
			
		||||
		ops = openBundledFont();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		ops = SDL_AllocRW();
 | 
			
		||||
		gState->fileSystem().openRead(*ops, path.constData(), FileSystem::Font);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// FIXME 0.9 is guesswork at this point
 | 
			
		||||
	font = TTF_OpenFontRW(ops, 1, (float) size * .90);
 | 
			
		||||
 | 
			
		||||
	if (!font)
 | 
			
		||||
		throw Exception(Exception::SDLError, "SDL: %s", SDL_GetError());
 | 
			
		||||
 | 
			
		||||
	p->hash.insert(key, font);
 | 
			
		||||
 | 
			
		||||
	return font;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct FontPrivate
 | 
			
		||||
{
 | 
			
		||||
	QByteArray name;
 | 
			
		||||
	int size;
 | 
			
		||||
	bool bold;
 | 
			
		||||
	bool italic;
 | 
			
		||||
	Color *color;
 | 
			
		||||
 | 
			
		||||
	Color colorTmp;
 | 
			
		||||
 | 
			
		||||
	static QByteArray defaultName;
 | 
			
		||||
	static int defaultSize;
 | 
			
		||||
	static bool defaultBold;
 | 
			
		||||
	static bool defaultItalic;
 | 
			
		||||
	static Color *defaultColor;
 | 
			
		||||
 | 
			
		||||
	static Color defaultColorTmp;
 | 
			
		||||
 | 
			
		||||
	TTF_Font *sdlFont;
 | 
			
		||||
 | 
			
		||||
	FontPrivate(const char *name = 0,
 | 
			
		||||
	            int size = 0)
 | 
			
		||||
	    : name(name ? QByteArray(name) : defaultName),
 | 
			
		||||
	      size(size ? size : defaultSize),
 | 
			
		||||
	      bold(defaultBold),
 | 
			
		||||
	      italic(defaultItalic),
 | 
			
		||||
	      color(&colorTmp),
 | 
			
		||||
	      colorTmp(*defaultColor)
 | 
			
		||||
	{
 | 
			
		||||
		sdlFont = gState->fontPool().request(this->name.constData(),
 | 
			
		||||
		                                     this->size);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
QByteArray FontPrivate::defaultName   = "Arial";
 | 
			
		||||
int        FontPrivate::defaultSize   = 22;
 | 
			
		||||
bool       FontPrivate::defaultBold   = false;
 | 
			
		||||
bool       FontPrivate::defaultItalic = false;
 | 
			
		||||
Color     *FontPrivate::defaultColor  = &FontPrivate::defaultColorTmp;
 | 
			
		||||
 | 
			
		||||
Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
 | 
			
		||||
 | 
			
		||||
bool Font::doesExist(const char *name)
 | 
			
		||||
{
 | 
			
		||||
	QByteArray path = QByteArray("fonts/") + QByteArray(name);
 | 
			
		||||
 | 
			
		||||
	return gState->fileSystem().exists(path.constData(), FileSystem::Font);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Font::Font(const char *name,
 | 
			
		||||
           int size)
 | 
			
		||||
{
 | 
			
		||||
	p = new FontPrivate(name, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Font::~Font()
 | 
			
		||||
{
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *Font::getName() const
 | 
			
		||||
{
 | 
			
		||||
	return p->name.constData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::setName(const char *value)
 | 
			
		||||
{
 | 
			
		||||
	p->name = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::setSize(int value)
 | 
			
		||||
{
 | 
			
		||||
	if (p->size == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->size = value;
 | 
			
		||||
	p->sdlFont = gState->fontPool().request(p->name.constData(), value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#undef CHK_DISP
 | 
			
		||||
#define CHK_DISP
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Font, Size, int, p->size)
 | 
			
		||||
DEF_ATTR_SIMPLE(Font, Bold, bool, p->bold)
 | 
			
		||||
DEF_ATTR_SIMPLE(Font, Italic, bool, p->italic)
 | 
			
		||||
DEF_ATTR_SIMPLE(Font, Color, Color*, p->color)
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultSize, int, FontPrivate::defaultSize)
 | 
			
		||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultBold, bool, FontPrivate::defaultBold)
 | 
			
		||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultItalic, bool, FontPrivate::defaultItalic)
 | 
			
		||||
DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color*, FontPrivate::defaultColor)
 | 
			
		||||
 | 
			
		||||
const char *Font::getDefaultName()
 | 
			
		||||
{
 | 
			
		||||
	return FontPrivate::defaultName.constData();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Font::setDefaultName(const char *value)
 | 
			
		||||
{
 | 
			
		||||
	FontPrivate::defaultName = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
_TTF_Font *Font::getSdlFont()
 | 
			
		||||
{
 | 
			
		||||
	int style = TTF_STYLE_NORMAL;
 | 
			
		||||
 | 
			
		||||
	if (p->bold)
 | 
			
		||||
		style |= TTF_STYLE_BOLD;
 | 
			
		||||
 | 
			
		||||
	if (p->italic)
 | 
			
		||||
		style |= TTF_STYLE_ITALIC;
 | 
			
		||||
 | 
			
		||||
	TTF_SetFontStyle(p->sdlFont, style);
 | 
			
		||||
 | 
			
		||||
	return p->sdlFont;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										76
									
								
								src/font.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/font.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
/*
 | 
			
		||||
** font.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef FONT_H
 | 
			
		||||
#define FONT_H
 | 
			
		||||
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
struct _TTF_Font;
 | 
			
		||||
struct FontPoolPrivate;
 | 
			
		||||
 | 
			
		||||
class FontPool
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	FontPool();
 | 
			
		||||
	~FontPool();
 | 
			
		||||
 | 
			
		||||
	_TTF_Font *request(const char *filename,
 | 
			
		||||
	                  int size);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	FontPoolPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FontPrivate;
 | 
			
		||||
 | 
			
		||||
class Font
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	static bool doesExist(const char *name);
 | 
			
		||||
 | 
			
		||||
	Font(const char *name = 0,
 | 
			
		||||
	     int size = 0);
 | 
			
		||||
	~Font();
 | 
			
		||||
 | 
			
		||||
	const char *getName() const;
 | 
			
		||||
	void setName(const char *value);
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Size,   int )
 | 
			
		||||
	DECL_ATTR( Bold,   bool )
 | 
			
		||||
	DECL_ATTR( Italic, bool )
 | 
			
		||||
	DECL_ATTR( Color,  Color* )
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultName,   const char* )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultSize,   int         )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultBold,   bool        )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultItalic, bool        )
 | 
			
		||||
	DECL_ATTR_STATIC( DefaultColor,  Color*      )
 | 
			
		||||
 | 
			
		||||
	/* internal */
 | 
			
		||||
	_TTF_Font *getSdlFont();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	FontPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // FONT_H
 | 
			
		||||
							
								
								
									
										388
									
								
								src/gl-util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								src/gl-util.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,388 @@
 | 
			
		|||
/*
 | 
			
		||||
** gl-util.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef GLUTIL_H
 | 
			
		||||
#define GLUTIL_H
 | 
			
		||||
 | 
			
		||||
#include "GL/glew.h"
 | 
			
		||||
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
/* Struct wrapping GLuint for some light type safety */
 | 
			
		||||
#define DEF_GL_ID \
 | 
			
		||||
struct ID \
 | 
			
		||||
{ \
 | 
			
		||||
	GLuint gl; \
 | 
			
		||||
	explicit ID(GLuint gl = 0)  \
 | 
			
		||||
	    : gl(gl)  \
 | 
			
		||||
	{}  \
 | 
			
		||||
	ID &operator=(const ID &o)  \
 | 
			
		||||
	{  \
 | 
			
		||||
		gl = o.gl;  \
 | 
			
		||||
		return *this; \
 | 
			
		||||
	}  \
 | 
			
		||||
	bool operator==(const ID &o) const  \
 | 
			
		||||
	{  \
 | 
			
		||||
		return gl == o.gl;  \
 | 
			
		||||
	}  \
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
namespace Tex
 | 
			
		||||
{
 | 
			
		||||
	DEF_GL_ID
 | 
			
		||||
 | 
			
		||||
	inline ID gen()
 | 
			
		||||
	{
 | 
			
		||||
		ID id;
 | 
			
		||||
		glGenTextures(1, &id.gl);
 | 
			
		||||
 | 
			
		||||
		return id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void del(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glDeleteTextures(1, &id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void bind(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glBindTexture(GL_TEXTURE_2D, id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void unbind()
 | 
			
		||||
	{
 | 
			
		||||
		bind(ID(0));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void bindMatrix(int width, int height, int xOffset = 0)
 | 
			
		||||
	{
 | 
			
		||||
		glMatrixMode(GL_TEXTURE);
 | 
			
		||||
		glLoadIdentity();
 | 
			
		||||
		glScalef(1.f / width, 1.f / height, 1.f);
 | 
			
		||||
		glTranslatef(xOffset, 0, 0);
 | 
			
		||||
		glMatrixMode(GL_MODELVIEW);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void bindWithMatrix(ID id, int width, int height, int xOffset = 0)
 | 
			
		||||
	{
 | 
			
		||||
		bind(id);
 | 
			
		||||
		bindMatrix(width, height, xOffset);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void uploadImage(GLsizei width, GLsizei height, const void *data, GLenum format)
 | 
			
		||||
	{
 | 
			
		||||
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, format, GL_UNSIGNED_BYTE, data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void uploadSubImage(GLint x, GLint y, GLsizei width, GLsizei height, const void *data, GLenum format)
 | 
			
		||||
	{
 | 
			
		||||
		glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, format, GL_UNSIGNED_BYTE, data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void allocEmpty(GLsizei width, GLsizei height)
 | 
			
		||||
	{
 | 
			
		||||
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void setRepeat(bool mode)
 | 
			
		||||
	{
 | 
			
		||||
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
 | 
			
		||||
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode ? GL_REPEAT : GL_CLAMP_TO_EDGE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void setSmooth(bool mode)
 | 
			
		||||
	{
 | 
			
		||||
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mode ? GL_LINEAR : GL_NEAREST);
 | 
			
		||||
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mode ? GL_LINEAR : GL_NEAREST);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace RB
 | 
			
		||||
{
 | 
			
		||||
	DEF_GL_ID
 | 
			
		||||
 | 
			
		||||
	inline ID gen()
 | 
			
		||||
	{
 | 
			
		||||
		ID id;
 | 
			
		||||
		glGenRenderbuffers(1, &id.gl);
 | 
			
		||||
 | 
			
		||||
		return id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void del(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glDeleteRenderbuffers(1, &id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void bind(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glBindRenderbuffer(GL_RENDERBUFFER, id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void unbind()
 | 
			
		||||
	{
 | 
			
		||||
		bind(ID(0));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void allocEmpty(GLsizei width, GLsizei height)
 | 
			
		||||
	{
 | 
			
		||||
		glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace FBO
 | 
			
		||||
{
 | 
			
		||||
	DEF_GL_ID
 | 
			
		||||
 | 
			
		||||
	enum Mode
 | 
			
		||||
	{
 | 
			
		||||
		Draw = 0,
 | 
			
		||||
		Read = 1,
 | 
			
		||||
		Default = 2
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	inline ID gen()
 | 
			
		||||
	{
 | 
			
		||||
		ID id;
 | 
			
		||||
		glGenFramebuffers(1, &id.gl);
 | 
			
		||||
 | 
			
		||||
		return id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void del(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glDeleteFramebuffers(1, &id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void bind(ID id, Mode mode = Default)
 | 
			
		||||
	{
 | 
			
		||||
		static const GLenum modes[] =
 | 
			
		||||
		{
 | 
			
		||||
			GL_DRAW_FRAMEBUFFER,
 | 
			
		||||
			GL_READ_FRAMEBUFFER,
 | 
			
		||||
			GL_FRAMEBUFFER
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		glBindFramebuffer(modes[mode], id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void unbind(Mode mode = Default)
 | 
			
		||||
	{
 | 
			
		||||
		bind(ID(0), mode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void setTexTarget(Tex::ID texTarget, unsigned colorAttach = 0)
 | 
			
		||||
	{
 | 
			
		||||
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_TEXTURE_2D, texTarget.gl, 0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void setRBTarget(RB::ID rbTarget, unsigned colorAttach = 0)
 | 
			
		||||
	{
 | 
			
		||||
		glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + colorAttach, GL_RENDERBUFFER, rbTarget.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void blit(int srcX, int srcY,
 | 
			
		||||
	                 int srcW, int srcH,
 | 
			
		||||
	                 int dstX, int dstY,
 | 
			
		||||
	                 int dstW, int dstH)
 | 
			
		||||
	{
 | 
			
		||||
		glBlitFramebuffer(srcX, srcY, srcX+srcW, srcY+srcH,
 | 
			
		||||
		                  dstX, dstY, dstX+dstW, dstY+dstH,
 | 
			
		||||
		                  GL_COLOR_BUFFER_BIT, GL_NEAREST);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void blit(int srcX, int srcY,
 | 
			
		||||
					 int dstX, int dstY,
 | 
			
		||||
					 int srcW, int srcH)
 | 
			
		||||
	{
 | 
			
		||||
		blit(srcX, srcY, srcW, srcH, dstX, dstY, srcW, srcH);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline Vec4 getPixel(int x, int y, int texWidth, int texHeight)
 | 
			
		||||
	{
 | 
			
		||||
		Vec4 pixel;
 | 
			
		||||
 | 
			
		||||
		glViewport(0, 0, texWidth, texHeight);
 | 
			
		||||
		glReadPixels(x, y, 1, 1, GL_RGBA, GL_FLOAT, &pixel.x);
 | 
			
		||||
 | 
			
		||||
		return pixel;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace VAO
 | 
			
		||||
{
 | 
			
		||||
	DEF_GL_ID
 | 
			
		||||
 | 
			
		||||
	inline ID gen()
 | 
			
		||||
	{
 | 
			
		||||
		ID id;
 | 
			
		||||
		glGenVertexArrays(1, &id.gl);
 | 
			
		||||
 | 
			
		||||
		return id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void del(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glDeleteVertexArrays(1, &id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void bind(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glBindVertexArray(id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline void unbind()
 | 
			
		||||
	{
 | 
			
		||||
		bind(ID(0));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<GLenum target>
 | 
			
		||||
struct GenericBO
 | 
			
		||||
{
 | 
			
		||||
	DEF_GL_ID
 | 
			
		||||
 | 
			
		||||
	inline static ID gen()
 | 
			
		||||
	{
 | 
			
		||||
		ID id;
 | 
			
		||||
		glGenBuffers(1, &id.gl);
 | 
			
		||||
 | 
			
		||||
		return id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline static void del(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glDeleteBuffers(1, &id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline static void bind(ID id)
 | 
			
		||||
	{
 | 
			
		||||
		glBindBuffer(target, id.gl);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline static void unbind()
 | 
			
		||||
	{
 | 
			
		||||
		bind(ID(0));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline static void uploadData(GLsizeiptr size, const GLvoid *data, GLenum usage = GL_STATIC_DRAW)
 | 
			
		||||
	{
 | 
			
		||||
		glBufferData(target, size, data, usage);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline static void uploadSubData(GLintptr offset, GLsizeiptr size, const GLvoid *data)
 | 
			
		||||
	{
 | 
			
		||||
		glBufferSubData(target, offset, size, data);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline static void allocEmpty(GLsizeiptr size, GLenum usage = GL_STATIC_DRAW)
 | 
			
		||||
	{
 | 
			
		||||
		uploadData(size, 0, usage);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct GenericBO<GL_ARRAY_BUFFER> VBO;
 | 
			
		||||
typedef struct GenericBO<GL_ELEMENT_ARRAY_BUFFER> IBO;
 | 
			
		||||
 | 
			
		||||
struct TexFBO
 | 
			
		||||
{
 | 
			
		||||
	Tex::ID tex;
 | 
			
		||||
	FBO::ID fbo;
 | 
			
		||||
	int width, height;
 | 
			
		||||
 | 
			
		||||
	TexFBO()
 | 
			
		||||
	    : tex(0), fbo(0), width(0), height(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool operator==(const TexFBO &other) const
 | 
			
		||||
	{
 | 
			
		||||
		return (tex == other.tex) && (fbo == other.fbo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void init(TexFBO &obj)
 | 
			
		||||
	{
 | 
			
		||||
		obj.tex = Tex::gen();
 | 
			
		||||
		obj.fbo = FBO::gen();
 | 
			
		||||
		Tex::bind(obj.tex);
 | 
			
		||||
		Tex::setRepeat(false);
 | 
			
		||||
		Tex::setSmooth(false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void allocEmpty(TexFBO &obj, int width, int height)
 | 
			
		||||
	{
 | 
			
		||||
		Tex::bind(obj.tex);
 | 
			
		||||
		Tex::allocEmpty(width, height);
 | 
			
		||||
		obj.width = width;
 | 
			
		||||
		obj.height = height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void linkFBO(TexFBO &obj)
 | 
			
		||||
	{
 | 
			
		||||
		FBO::bind(obj.fbo);
 | 
			
		||||
		FBO::setTexTarget(obj.tex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void fini(TexFBO &obj)
 | 
			
		||||
	{
 | 
			
		||||
		FBO::del(obj.fbo);
 | 
			
		||||
		Tex::del(obj.tex);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct RBFBO
 | 
			
		||||
{
 | 
			
		||||
	RB::ID rb;
 | 
			
		||||
	FBO::ID fbo;
 | 
			
		||||
	int width, height;
 | 
			
		||||
 | 
			
		||||
	RBFBO()
 | 
			
		||||
	    : rb(0), fbo(0), width(0), height(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	static inline void init(RBFBO &obj)
 | 
			
		||||
	{
 | 
			
		||||
		obj.rb = RB::gen();
 | 
			
		||||
		obj.fbo = FBO::gen();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void allocEmpty(RBFBO &obj, int width, int height)
 | 
			
		||||
	{
 | 
			
		||||
		RB::bind(obj.rb);
 | 
			
		||||
		RB::allocEmpty(width, height);
 | 
			
		||||
		obj.width = width;
 | 
			
		||||
		obj.height = height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void linkFBO(RBFBO &obj)
 | 
			
		||||
	{
 | 
			
		||||
		FBO::bind(obj.fbo);
 | 
			
		||||
		FBO::setRBTarget(obj.rb);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static inline void fini(RBFBO &obj)
 | 
			
		||||
	{
 | 
			
		||||
		FBO::del(obj.fbo);
 | 
			
		||||
		RB::del(obj.rb);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // GLUTIL_H
 | 
			
		||||
							
								
								
									
										66
									
								
								src/global-ibo.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/global-ibo.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
/*
 | 
			
		||||
** global-ibo.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef GLOBALIBO_H
 | 
			
		||||
#define GLOBALIBO_H
 | 
			
		||||
 | 
			
		||||
#include <gl-util.h>
 | 
			
		||||
#include <QVector>
 | 
			
		||||
 | 
			
		||||
struct GlobalIBO
 | 
			
		||||
{
 | 
			
		||||
	IBO::ID ibo;
 | 
			
		||||
	QVector<quint32> buffer;
 | 
			
		||||
 | 
			
		||||
	GlobalIBO()
 | 
			
		||||
	{
 | 
			
		||||
		ibo = IBO::gen();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~GlobalIBO()
 | 
			
		||||
	{
 | 
			
		||||
		IBO::del(ibo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void ensureSize(int quadCount)
 | 
			
		||||
	{
 | 
			
		||||
		if (buffer.size() >= quadCount*6)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		int startInd = buffer.size() / 6;
 | 
			
		||||
		buffer.reserve(quadCount*6);
 | 
			
		||||
 | 
			
		||||
		for (int i = startInd; i < quadCount; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			static const int indTemp[] = { 0, 1, 2, 2, 3, 0 };
 | 
			
		||||
 | 
			
		||||
			for (int j = 0; j < 6; ++j)
 | 
			
		||||
				buffer.append(i * 4 + indTemp[j]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		IBO::bind(ibo);
 | 
			
		||||
		IBO::uploadData(buffer.count() * sizeof(int),
 | 
			
		||||
		                buffer.constData());
 | 
			
		||||
		IBO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // GLOBALIBO_H
 | 
			
		||||
							
								
								
									
										271
									
								
								src/globalstate.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								src/globalstate.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,271 @@
 | 
			
		|||
/*
 | 
			
		||||
** globalstate.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "filesystem.h"
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
#include "input.h"
 | 
			
		||||
#include "audio.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
#include "shader.h"
 | 
			
		||||
#include "texpool.h"
 | 
			
		||||
#include "font.h"
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "global-ibo.h"
 | 
			
		||||
#include "binding.h"
 | 
			
		||||
 | 
			
		||||
#include <QFile>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
GlobalState *GlobalState::instance = 0;
 | 
			
		||||
static GlobalIBO *globalIBO = 0;
 | 
			
		||||
 | 
			
		||||
#define GAME_ARCHIVE "Game.rgssad"
 | 
			
		||||
 | 
			
		||||
struct GlobalStatePrivate
 | 
			
		||||
{
 | 
			
		||||
	void *bindingData;
 | 
			
		||||
	SDL_Window *sdlWindow;
 | 
			
		||||
	Scene *screen;
 | 
			
		||||
 | 
			
		||||
	FileSystem fileSystem;
 | 
			
		||||
 | 
			
		||||
	EventThread &eThread;
 | 
			
		||||
	RGSSThreadData &rtData;
 | 
			
		||||
	Config &config;
 | 
			
		||||
 | 
			
		||||
	Graphics graphics;
 | 
			
		||||
	Input input;
 | 
			
		||||
	Audio audio;
 | 
			
		||||
 | 
			
		||||
	GLState _glState;
 | 
			
		||||
 | 
			
		||||
	SpriteShader spriteShader;
 | 
			
		||||
	TransShader transShader;
 | 
			
		||||
	SimpleTransShader sTransShader;
 | 
			
		||||
	HueShader hueShader;
 | 
			
		||||
	BltShader bltShader;
 | 
			
		||||
 | 
			
		||||
	TexPool texPool;
 | 
			
		||||
	FontPool fontPool;
 | 
			
		||||
 | 
			
		||||
	Font *defaultFont;
 | 
			
		||||
 | 
			
		||||
	Tex::ID globalTex;
 | 
			
		||||
	int globalTexW, globalTexH;
 | 
			
		||||
 | 
			
		||||
	TexFBO gpTexFBO;
 | 
			
		||||
 | 
			
		||||
	unsigned int stampCounter;
 | 
			
		||||
 | 
			
		||||
	GlobalStatePrivate(RGSSThreadData *threadData)
 | 
			
		||||
	    : bindingData(0),
 | 
			
		||||
	      sdlWindow(threadData->window),
 | 
			
		||||
	      fileSystem(threadData->argv0),
 | 
			
		||||
	      eThread(*threadData->ethread),
 | 
			
		||||
	      rtData(*threadData),
 | 
			
		||||
	      config(threadData->config),
 | 
			
		||||
	      graphics(threadData),
 | 
			
		||||
	      stampCounter(0)
 | 
			
		||||
	{
 | 
			
		||||
		if (!config.gameFolder.isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			int unused = chdir(config.gameFolder.constData());
 | 
			
		||||
			(void) unused;
 | 
			
		||||
			fileSystem.addPath(config.gameFolder.constData());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// FIXME find out correct archive filename
 | 
			
		||||
		QByteArray archPath = threadData->config.gameFolder + "/" GAME_ARCHIVE;
 | 
			
		||||
 | 
			
		||||
		if (QFile::exists(archPath.constData()))
 | 
			
		||||
			fileSystem.addPath(archPath.constData());
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < config.rtps.count(); ++i)
 | 
			
		||||
			fileSystem.addPath(config.rtps[i].constData());
 | 
			
		||||
 | 
			
		||||
		globalTexW = 128;
 | 
			
		||||
		globalTexH = 64;
 | 
			
		||||
 | 
			
		||||
		globalTex = Tex::gen();
 | 
			
		||||
		Tex::bind(globalTex);
 | 
			
		||||
		Tex::setRepeat(false);
 | 
			
		||||
		Tex::setSmooth(false);
 | 
			
		||||
		Tex::allocEmpty(globalTexW, globalTexH);
 | 
			
		||||
 | 
			
		||||
		TexFBO::init(gpTexFBO);
 | 
			
		||||
		/* Reuse starting values */
 | 
			
		||||
		TexFBO::allocEmpty(gpTexFBO, globalTexW, globalTexH);
 | 
			
		||||
		TexFBO::linkFBO(gpTexFBO);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~GlobalStatePrivate()
 | 
			
		||||
	{
 | 
			
		||||
		Tex::del(globalTex);
 | 
			
		||||
		TexFBO::fini(gpTexFBO);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void GlobalState::initInstance(RGSSThreadData *threadData)
 | 
			
		||||
{
 | 
			
		||||
	globalIBO = new GlobalIBO();
 | 
			
		||||
	globalIBO->ensureSize(1);
 | 
			
		||||
 | 
			
		||||
	GlobalState *state = new GlobalState(threadData);
 | 
			
		||||
 | 
			
		||||
	GlobalState::instance = state;
 | 
			
		||||
 | 
			
		||||
	state->p->defaultFont = new Font();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::finiInstance()
 | 
			
		||||
{
 | 
			
		||||
	delete GlobalState::instance->p->defaultFont;
 | 
			
		||||
 | 
			
		||||
	delete GlobalState::instance;
 | 
			
		||||
 | 
			
		||||
	delete globalIBO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::setScreen(Scene &screen)
 | 
			
		||||
{
 | 
			
		||||
	p->screen = &screen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define GSATT(type, lower) \
 | 
			
		||||
	type GlobalState :: lower() \
 | 
			
		||||
	{ \
 | 
			
		||||
		return p->lower; \
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
GSATT(void*, bindingData)
 | 
			
		||||
GSATT(SDL_Window*, sdlWindow)
 | 
			
		||||
GSATT(Scene*, screen)
 | 
			
		||||
GSATT(FileSystem&, fileSystem)
 | 
			
		||||
GSATT(EventThread&, eThread)
 | 
			
		||||
GSATT(RGSSThreadData&, rtData)
 | 
			
		||||
GSATT(Config&, config)
 | 
			
		||||
GSATT(Graphics&, graphics)
 | 
			
		||||
GSATT(Input&, input)
 | 
			
		||||
GSATT(Audio&, audio)
 | 
			
		||||
GSATT(GLState&, _glState)
 | 
			
		||||
GSATT(SpriteShader&, spriteShader)
 | 
			
		||||
GSATT(TransShader&, transShader)
 | 
			
		||||
GSATT(SimpleTransShader&, sTransShader)
 | 
			
		||||
GSATT(HueShader&, hueShader)
 | 
			
		||||
GSATT(BltShader&, bltShader)
 | 
			
		||||
GSATT(TexPool&, texPool)
 | 
			
		||||
GSATT(FontPool&, fontPool)
 | 
			
		||||
 | 
			
		||||
void GlobalState::setBindingData(void *data)
 | 
			
		||||
{
 | 
			
		||||
	p->bindingData = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::ensureQuadIBO(int minSize)
 | 
			
		||||
{
 | 
			
		||||
	globalIBO->ensureSize(minSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::bindQuadIBO()
 | 
			
		||||
{
 | 
			
		||||
	IBO::bind(globalIBO->ibo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::bindTex()
 | 
			
		||||
{
 | 
			
		||||
	Tex::bind(p->globalTex);
 | 
			
		||||
	Tex::allocEmpty(p->globalTexW, p->globalTexH);
 | 
			
		||||
	Tex::bindMatrix(p->globalTexW, p->globalTexH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::ensureTexSize(int minW, int minH, Vec2 ¤tSizeOut)
 | 
			
		||||
{
 | 
			
		||||
	if (minW > p->globalTexW)
 | 
			
		||||
		p->globalTexW = findNextPow2(minW);
 | 
			
		||||
 | 
			
		||||
	if (minH > p->globalTexH)
 | 
			
		||||
		p->globalTexH = findNextPow2(minH);
 | 
			
		||||
 | 
			
		||||
	currentSizeOut = Vec2(p->globalTexW, p->globalTexH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TexFBO &GlobalState::gpTexFBO(int minW, int minH)
 | 
			
		||||
{
 | 
			
		||||
	bool needResize = false;
 | 
			
		||||
 | 
			
		||||
	if (minW > p->gpTexFBO.width)
 | 
			
		||||
	{
 | 
			
		||||
		p->gpTexFBO.width = findNextPow2(minW);
 | 
			
		||||
		needResize = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (minH > p->gpTexFBO.height)
 | 
			
		||||
	{
 | 
			
		||||
		p->gpTexFBO.height = findNextPow2(minH);
 | 
			
		||||
		needResize = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (needResize)
 | 
			
		||||
	{
 | 
			
		||||
		Tex::bind(p->gpTexFBO.tex);
 | 
			
		||||
		Tex::allocEmpty(p->gpTexFBO.width, p->gpTexFBO.height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return p->gpTexFBO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GlobalState::checkShutdown()
 | 
			
		||||
{
 | 
			
		||||
	if (!p->rtData.rqTerm)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->rtData.rqTermAck = true;
 | 
			
		||||
	p->texPool.disable();
 | 
			
		||||
	scriptBinding->terminate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Font &GlobalState::defaultFont()
 | 
			
		||||
{
 | 
			
		||||
	return *p->defaultFont;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int GlobalState::genTimeStamp()
 | 
			
		||||
{
 | 
			
		||||
	return p->stampCounter++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GlobalState::GlobalState(RGSSThreadData *threadData)
 | 
			
		||||
{
 | 
			
		||||
	p = new GlobalStatePrivate(threadData);
 | 
			
		||||
	p->screen = p->graphics.getScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GlobalState::~GlobalState()
 | 
			
		||||
{
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								src/globalstate.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/globalstate.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,120 @@
 | 
			
		|||
/*
 | 
			
		||||
** globalstate.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef GLOBALSTATE_H
 | 
			
		||||
#define GLOBALSTATE_H
 | 
			
		||||
 | 
			
		||||
#include "sigc++/signal.h"
 | 
			
		||||
 | 
			
		||||
#define gState GlobalState::instance
 | 
			
		||||
#define glState gState->_glState()
 | 
			
		||||
 | 
			
		||||
struct GlobalStatePrivate;
 | 
			
		||||
struct RGSSThreadData;
 | 
			
		||||
struct GlobalIBO;
 | 
			
		||||
struct mrb_state;
 | 
			
		||||
struct SDL_Window;
 | 
			
		||||
struct TexFBO;
 | 
			
		||||
 | 
			
		||||
class Scene;
 | 
			
		||||
class FileSystem;
 | 
			
		||||
class EventThread;
 | 
			
		||||
class Graphics;
 | 
			
		||||
class Input;
 | 
			
		||||
class Audio;
 | 
			
		||||
class GLState;
 | 
			
		||||
class SpriteShader;
 | 
			
		||||
class TransShader;
 | 
			
		||||
class SimpleTransShader;
 | 
			
		||||
class HueShader;
 | 
			
		||||
class BltShader;
 | 
			
		||||
class TexPool;
 | 
			
		||||
class FontPool;
 | 
			
		||||
class Font;
 | 
			
		||||
struct GlobalIBO;
 | 
			
		||||
struct Config;
 | 
			
		||||
struct Vec2;
 | 
			
		||||
 | 
			
		||||
struct GlobalState
 | 
			
		||||
{
 | 
			
		||||
	void *bindingData();
 | 
			
		||||
	void setBindingData(void *data);
 | 
			
		||||
 | 
			
		||||
	SDL_Window *sdlWindow();
 | 
			
		||||
 | 
			
		||||
	Scene *screen();
 | 
			
		||||
	void setScreen(Scene &screen);
 | 
			
		||||
 | 
			
		||||
	FileSystem &fileSystem();
 | 
			
		||||
 | 
			
		||||
	EventThread &eThread();
 | 
			
		||||
	RGSSThreadData &rtData();
 | 
			
		||||
	Config &config();
 | 
			
		||||
 | 
			
		||||
	Graphics &graphics();
 | 
			
		||||
	Input &input();
 | 
			
		||||
	Audio &audio();
 | 
			
		||||
 | 
			
		||||
	GLState &_glState();
 | 
			
		||||
 | 
			
		||||
	SpriteShader &spriteShader();
 | 
			
		||||
	TransShader &transShader();
 | 
			
		||||
	SimpleTransShader &sTransShader();
 | 
			
		||||
	HueShader &hueShader();
 | 
			
		||||
	BltShader &bltShader();
 | 
			
		||||
 | 
			
		||||
	TexPool &texPool();
 | 
			
		||||
	FontPool &fontPool();
 | 
			
		||||
 | 
			
		||||
	Font &defaultFont();
 | 
			
		||||
 | 
			
		||||
	sigc::signal<void> prepareDraw;
 | 
			
		||||
 | 
			
		||||
	unsigned int genTimeStamp();
 | 
			
		||||
 | 
			
		||||
	/* Returns global quad IBO, and ensures it has indices
 | 
			
		||||
	 * for at least minSize quads */
 | 
			
		||||
	void ensureQuadIBO(int minSize);
 | 
			
		||||
	void bindQuadIBO();
 | 
			
		||||
 | 
			
		||||
	/* Global general purpose texture */
 | 
			
		||||
	void bindTex();
 | 
			
		||||
	void ensureTexSize(int minW, int minH, Vec2 ¤tSizeOut);
 | 
			
		||||
 | 
			
		||||
	TexFBO &gpTexFBO(int minW, int minH);
 | 
			
		||||
 | 
			
		||||
	/* Checks EventThread's shutdown request flag and if set,
 | 
			
		||||
	 * requests the binding to terminate. In this case, this
 | 
			
		||||
	 * function will most likely not return */
 | 
			
		||||
	void checkShutdown();
 | 
			
		||||
 | 
			
		||||
	static GlobalState *instance;
 | 
			
		||||
	static void initInstance(RGSSThreadData *threadData);
 | 
			
		||||
	static void finiInstance();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GlobalState(RGSSThreadData *threadData);
 | 
			
		||||
	~GlobalState();
 | 
			
		||||
 | 
			
		||||
	GlobalStatePrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // GLOBALSTATE_H
 | 
			
		||||
							
								
								
									
										139
									
								
								src/glstate.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								src/glstate.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,139 @@
 | 
			
		|||
/*
 | 
			
		||||
** glstate.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
#include "GL/glew.h"
 | 
			
		||||
#include "SDL2/SDL_rect.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
 | 
			
		||||
void GLClearColor::apply(const Vec4 &value)
 | 
			
		||||
{
 | 
			
		||||
	glClearColor(value.x, value.y, value.z, value.w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScissorBox::apply(const IntRect &value)
 | 
			
		||||
{
 | 
			
		||||
	glScissor(value.x, value.y, value.w, value.h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScissorBox::setIntersect(const IntRect &value)
 | 
			
		||||
{
 | 
			
		||||
	IntRect ¤t = get();
 | 
			
		||||
 | 
			
		||||
	SDL_Rect r1 = { current.x, current.y, current.w, current.h };
 | 
			
		||||
	SDL_Rect r2 = { value.x,   value.y,   value.w,   value.h };
 | 
			
		||||
 | 
			
		||||
	SDL_Rect result;
 | 
			
		||||
	if (!SDL_IntersectRect(&r1, &r2, &result))
 | 
			
		||||
		result.w = result.h = 0;
 | 
			
		||||
 | 
			
		||||
	set(IntRect(result.x, result.y, result.w, result.h));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLScissorTest::apply(const bool &value)
 | 
			
		||||
{
 | 
			
		||||
	value ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLTexture2D::apply(const bool &value)
 | 
			
		||||
{
 | 
			
		||||
	value ? glEnable(GL_TEXTURE_2D) : glDisable(GL_TEXTURE_2D);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLBlendMode::apply(const BlendType &value)
 | 
			
		||||
{
 | 
			
		||||
	switch (value)
 | 
			
		||||
	{
 | 
			
		||||
	case BlendNone :
 | 
			
		||||
		glBlendEquation(GL_FUNC_ADD);
 | 
			
		||||
		glBlendFunc(GL_ONE, GL_ZERO);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case BlendNormal :
 | 
			
		||||
		glBlendEquation(GL_FUNC_ADD);
 | 
			
		||||
		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
 | 
			
		||||
		                    GL_ONE,       GL_ONE_MINUS_SRC_ALPHA);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case BlendAddition :
 | 
			
		||||
		glBlendEquation(GL_FUNC_ADD);
 | 
			
		||||
		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE,
 | 
			
		||||
		                    GL_ONE,       GL_ONE);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case BlendSubstraction :
 | 
			
		||||
		// FIXME Alpha calculation is untested
 | 
			
		||||
		glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
 | 
			
		||||
		glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE,
 | 
			
		||||
		                    GL_ONE,       GL_ONE);
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLViewport::apply(const IntRect &value)
 | 
			
		||||
{
 | 
			
		||||
	glViewport(value.x, value.y, value.w, value.h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void GLState::setViewport(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	viewport.set(IntRect(0, 0, width, height));
 | 
			
		||||
 | 
			
		||||
	glMatrixMode(GL_PROJECTION);
 | 
			
		||||
	glLoadIdentity();
 | 
			
		||||
	glOrtho(0, width, 0, height, 0, 1);
 | 
			
		||||
	glMatrixMode(GL_MODELVIEW);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLState::pushSetViewport(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	viewport.pushSet(IntRect(0, 0, width, height));
 | 
			
		||||
 | 
			
		||||
	glMatrixMode(GL_PROJECTION);
 | 
			
		||||
	glPushMatrix();
 | 
			
		||||
	glLoadIdentity();
 | 
			
		||||
	glOrtho(0, width, 0, height, 0, 1);
 | 
			
		||||
	glMatrixMode(GL_MODELVIEW);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GLState::popViewport()
 | 
			
		||||
{
 | 
			
		||||
	viewport.pop();
 | 
			
		||||
 | 
			
		||||
	glMatrixMode(GL_PROJECTION);
 | 
			
		||||
	glPopMatrix();
 | 
			
		||||
	glMatrixMode(GL_MODELVIEW);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLState::Caps::Caps()
 | 
			
		||||
{
 | 
			
		||||
	glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLState::GLState()
 | 
			
		||||
{
 | 
			
		||||
	clearColor.init(Vec4(0, 0, 0, 1));
 | 
			
		||||
	blendMode.init(BlendNormal);
 | 
			
		||||
	scissorTest.init(false);
 | 
			
		||||
	scissorBox.init(IntRect(0, 0, 640, 480));
 | 
			
		||||
	texture2D.init(true);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										145
									
								
								src/glstate.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								src/glstate.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,145 @@
 | 
			
		|||
/*
 | 
			
		||||
** glstate.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef GLSTATE_H
 | 
			
		||||
#define GLSTATE_H
 | 
			
		||||
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include <QStack>
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct GLProperty
 | 
			
		||||
{
 | 
			
		||||
	void init(const T &value)
 | 
			
		||||
	{
 | 
			
		||||
		current = value;
 | 
			
		||||
		apply(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void push() { stack.push(current); }
 | 
			
		||||
	void pop()  { set(stack.pop()); }
 | 
			
		||||
	T &get()    { return current; }
 | 
			
		||||
	void set(const T &value)
 | 
			
		||||
	{
 | 
			
		||||
		if (value == current)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		init(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void pushSet(const T &value)
 | 
			
		||||
	{
 | 
			
		||||
		push();
 | 
			
		||||
		set(value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	virtual void apply(const T &value) = 0;
 | 
			
		||||
 | 
			
		||||
	T current;
 | 
			
		||||
	QStack<T> stack;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Not needed
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct GLPropSaver
 | 
			
		||||
{
 | 
			
		||||
	GLPropSaver(GLProperty<T> &p)
 | 
			
		||||
	    : p(p)
 | 
			
		||||
	{
 | 
			
		||||
		p.push();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~GLPropSaver()
 | 
			
		||||
	{
 | 
			
		||||
		p.pop();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GLProperty<T> &p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GLClearColor : public GLProperty<Vec4>
 | 
			
		||||
{
 | 
			
		||||
	void apply(const Vec4 &);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GLScissorBox : public GLProperty<IntRect>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	/* Sets the intersection of the current box with value */
 | 
			
		||||
	void setIntersect(const IntRect &value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void apply(const IntRect &value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GLScissorTest : public GLProperty<bool>
 | 
			
		||||
{
 | 
			
		||||
	void apply(const bool &value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GLTexture2D : public GLProperty<bool>
 | 
			
		||||
{
 | 
			
		||||
	void apply(const bool &value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GLBlendMode : public GLProperty<BlendType>
 | 
			
		||||
{
 | 
			
		||||
	void apply(const BlendType &value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class GLViewport : public GLProperty<IntRect>
 | 
			
		||||
{
 | 
			
		||||
	void apply(const IntRect &value);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GLState
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	GLClearColor clearColor;
 | 
			
		||||
	GLScissorBox scissorBox;
 | 
			
		||||
	GLScissorTest scissorTest;
 | 
			
		||||
	GLTexture2D texture2D;
 | 
			
		||||
	GLBlendMode blendMode;
 | 
			
		||||
	GLViewport viewport;
 | 
			
		||||
 | 
			
		||||
	/* These functions pushSet/pop both the viewport
 | 
			
		||||
	 * and a glOrtho projection matrix.
 | 
			
		||||
	 * Useful for setting up rendering to FBOs of differing sizes */
 | 
			
		||||
	void setViewport(int width, int height);
 | 
			
		||||
	void pushSetViewport(int width, int height);
 | 
			
		||||
	void popViewport();
 | 
			
		||||
 | 
			
		||||
	struct Caps
 | 
			
		||||
	{
 | 
			
		||||
		int maxTexSize;
 | 
			
		||||
 | 
			
		||||
		Caps();
 | 
			
		||||
 | 
			
		||||
	} caps;
 | 
			
		||||
 | 
			
		||||
	GLState();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // GLSTATE_H
 | 
			
		||||
							
								
								
									
										855
									
								
								src/graphics.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										855
									
								
								src/graphics.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,855 @@
 | 
			
		|||
/*
 | 
			
		||||
** graphics.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "graphics.h"
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
#include "shader.h"
 | 
			
		||||
#include "scene.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
#include "texpool.h"
 | 
			
		||||
#include "bitmap.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "binding.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_video.h"
 | 
			
		||||
#include "SDL2/SDL_timer.h"
 | 
			
		||||
 | 
			
		||||
#include "stdint.h"
 | 
			
		||||
 | 
			
		||||
#include "SFML/System/Clock.hpp"
 | 
			
		||||
 | 
			
		||||
struct TimerQuery
 | 
			
		||||
{
 | 
			
		||||
	GLuint query;
 | 
			
		||||
	static bool queryActive;
 | 
			
		||||
	bool thisQueryActive;
 | 
			
		||||
 | 
			
		||||
	TimerQuery()
 | 
			
		||||
	    : thisQueryActive(false)
 | 
			
		||||
	{
 | 
			
		||||
		glGenQueries(1, &query);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void begin()
 | 
			
		||||
	{
 | 
			
		||||
		if (queryActive)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (thisQueryActive)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		glBeginQuery(GL_TIME_ELAPSED, query);
 | 
			
		||||
		queryActive = true;
 | 
			
		||||
		thisQueryActive = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void end()
 | 
			
		||||
	{
 | 
			
		||||
		if (!thisQueryActive)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		glEndQuery(GL_TIME_ELAPSED);
 | 
			
		||||
		queryActive = false;
 | 
			
		||||
		thisQueryActive = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool getResult(GLuint64 *result)
 | 
			
		||||
	{
 | 
			
		||||
		if (thisQueryActive)
 | 
			
		||||
			return false;
 | 
			
		||||
 | 
			
		||||
		GLint isReady;
 | 
			
		||||
		glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
 | 
			
		||||
 | 
			
		||||
		if (isReady != GL_TRUE)
 | 
			
		||||
		{
 | 
			
		||||
//			qDebug() << "TimerQuery result not ready";
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		glGetQueryObjectui64v(query, GL_QUERY_RESULT, result);
 | 
			
		||||
 | 
			
		||||
		if (glGetError() == GL_INVALID_OPERATION)
 | 
			
		||||
		{
 | 
			
		||||
			qDebug() << "Something went wrong with getting TimerQuery results";
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	GLuint64 getResultSync()
 | 
			
		||||
	{
 | 
			
		||||
		if (thisQueryActive)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		GLuint64 result;
 | 
			
		||||
		GLint isReady = GL_FALSE;
 | 
			
		||||
 | 
			
		||||
		while (isReady == GL_FALSE)
 | 
			
		||||
			glGetQueryObjectiv(query, GL_QUERY_RESULT_AVAILABLE, &isReady);
 | 
			
		||||
 | 
			
		||||
		glGetQueryObjectui64v(query, GL_QUERY_RESULT, &result);
 | 
			
		||||
 | 
			
		||||
		return result;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~TimerQuery()
 | 
			
		||||
	{
 | 
			
		||||
		if (thisQueryActive)
 | 
			
		||||
			end();
 | 
			
		||||
 | 
			
		||||
		glDeleteQueries(1, &query);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool TimerQuery::queryActive = false;
 | 
			
		||||
 | 
			
		||||
struct GPUTimer
 | 
			
		||||
{
 | 
			
		||||
	TimerQuery queries[2];
 | 
			
		||||
	const int iter;
 | 
			
		||||
 | 
			
		||||
	uchar ind;
 | 
			
		||||
	quint64 acc;
 | 
			
		||||
	qint32 counter;
 | 
			
		||||
	bool first;
 | 
			
		||||
 | 
			
		||||
	GPUTimer(int iter)
 | 
			
		||||
	    : iter(iter),
 | 
			
		||||
	      ind(0),
 | 
			
		||||
	      acc(0),
 | 
			
		||||
	      counter(0),
 | 
			
		||||
	      first(true)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void startTiming()
 | 
			
		||||
	{
 | 
			
		||||
		queries[ind].begin();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void endTiming()
 | 
			
		||||
	{
 | 
			
		||||
		queries[ind].end();
 | 
			
		||||
 | 
			
		||||
		if (first)
 | 
			
		||||
		{
 | 
			
		||||
			first = false;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		swapInd();
 | 
			
		||||
 | 
			
		||||
		GLuint64 result;
 | 
			
		||||
		if (!queries[ind].getResult(&result))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		acc += result;
 | 
			
		||||
 | 
			
		||||
		if (++counter < iter)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		qDebug() << "  Avg. GPU time:" << ((double) acc / (iter * 1000 * 1000)) << "ms";
 | 
			
		||||
		acc = counter = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void swapInd()
 | 
			
		||||
	{
 | 
			
		||||
		ind = ind ? 0 : 1;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CPUTimer
 | 
			
		||||
{
 | 
			
		||||
	const int iter;
 | 
			
		||||
 | 
			
		||||
	quint64 acc;
 | 
			
		||||
	qint32 counter;
 | 
			
		||||
	sf::Clock clock;
 | 
			
		||||
 | 
			
		||||
	CPUTimer(int iter)
 | 
			
		||||
	    : iter(iter),
 | 
			
		||||
	      acc(0),
 | 
			
		||||
	      counter(0)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void startTiming()
 | 
			
		||||
	{
 | 
			
		||||
		clock.restart();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void endTiming()
 | 
			
		||||
	{
 | 
			
		||||
		acc += clock.getElapsedTime().asMicroseconds();
 | 
			
		||||
 | 
			
		||||
		if (++counter < iter)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		qDebug() << "Avg. CPU time:" << ((double) acc / (iter * 1000)) << "ms";
 | 
			
		||||
		acc = counter = 0;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PingPong
 | 
			
		||||
{
 | 
			
		||||
	TexFBO rt[2];
 | 
			
		||||
	unsigned srcInd, dstInd;
 | 
			
		||||
	int screenW, screenH;
 | 
			
		||||
 | 
			
		||||
	PingPong(int screenW, int screenH)
 | 
			
		||||
	    : srcInd(0), dstInd(1),
 | 
			
		||||
	      screenW(screenW), screenH(screenH)
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < 2; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			TexFBO::init(rt[i]);
 | 
			
		||||
			TexFBO::allocEmpty(rt[i], screenW, screenH);
 | 
			
		||||
			TexFBO::linkFBO(rt[i]);
 | 
			
		||||
			glClearColor(0, 0, 0, 1);
 | 
			
		||||
			glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~PingPong()
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < 2; ++i)
 | 
			
		||||
			TexFBO::fini(rt[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Binds FBO of last good buffer for reading */
 | 
			
		||||
	void bindLastBuffer()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::bind(rt[dstInd].fbo, FBO::Read);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Better not call this during render cycles */
 | 
			
		||||
	void resize(int width, int height)
 | 
			
		||||
	{
 | 
			
		||||
		screenW = width;
 | 
			
		||||
		screenH = height;
 | 
			
		||||
		for (int i = 0; i < 2; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			Tex::bind(rt[i].tex);
 | 
			
		||||
			Tex::allocEmpty(width, height);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void startRender()
 | 
			
		||||
	{
 | 
			
		||||
		bind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void swapRender()
 | 
			
		||||
	{
 | 
			
		||||
		swapIndices();
 | 
			
		||||
 | 
			
		||||
		/* Discard dest buffer */
 | 
			
		||||
		Tex::bind(rt[dstInd].tex);
 | 
			
		||||
		Tex::allocEmpty(screenW, screenH);
 | 
			
		||||
 | 
			
		||||
		bind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void blitFBOs()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::blit(0, 0, 0, 0, screenW, screenH);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void finishRender()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::unbind(FBO::Draw);
 | 
			
		||||
		FBO::bind(rt[dstInd].fbo, FBO::Read);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void bind()
 | 
			
		||||
	{
 | 
			
		||||
		Tex::bindWithMatrix(rt[srcInd].tex, screenW, screenH, true);
 | 
			
		||||
		FBO::bind(rt[srcInd].fbo, FBO::Read);
 | 
			
		||||
		FBO::bind(rt[dstInd].fbo, FBO::Draw);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void swapIndices()
 | 
			
		||||
	{
 | 
			
		||||
		unsigned tmp = srcInd;
 | 
			
		||||
		srcInd = dstInd;
 | 
			
		||||
		dstInd = tmp;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ScreenScene : public Scene
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	ScreenScene(int width, int height)
 | 
			
		||||
	    : pp(width, height),
 | 
			
		||||
	      brightEffect(false),
 | 
			
		||||
	      actW(width), actH(height)
 | 
			
		||||
	{
 | 
			
		||||
		updateReso(width, height);
 | 
			
		||||
		brightnessQuad.setColor(Vec4());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void composite()
 | 
			
		||||
	{
 | 
			
		||||
		const int w = geometry.rect.w;
 | 
			
		||||
		const int h = geometry.rect.h;
 | 
			
		||||
 | 
			
		||||
		gState->prepareDraw();
 | 
			
		||||
 | 
			
		||||
		pp.startRender();
 | 
			
		||||
 | 
			
		||||
		glState.setViewport(w, h);
 | 
			
		||||
 | 
			
		||||
		glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
		Scene::composite();
 | 
			
		||||
 | 
			
		||||
		if (brightEffect)
 | 
			
		||||
		{
 | 
			
		||||
			glState.texture2D.pushSet(false);
 | 
			
		||||
			brightnessQuad.draw();
 | 
			
		||||
			glState.texture2D.pop();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		pp.finishRender();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void requestViewportRender(Vec4 &c, Vec4 &f, Vec4 &t)
 | 
			
		||||
	{
 | 
			
		||||
		pp.swapRender();
 | 
			
		||||
		pp.blitFBOs();
 | 
			
		||||
 | 
			
		||||
		SpriteShader &shader = gState->spriteShader();
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.resetUniforms();
 | 
			
		||||
		shader.setColor(c);
 | 
			
		||||
		shader.setFlash(f);
 | 
			
		||||
		shader.setTone(t);
 | 
			
		||||
 | 
			
		||||
		glState.blendMode.pushSet(BlendNone);
 | 
			
		||||
 | 
			
		||||
		Tex::bindMatrix(geometry.rect.w, geometry.rect.h);
 | 
			
		||||
		screenQuad.draw();
 | 
			
		||||
 | 
			
		||||
		glState.blendMode.pop();
 | 
			
		||||
		shader.unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setBrightness(float norm)
 | 
			
		||||
	{
 | 
			
		||||
		brightnessQuad.setColor(Vec4(0, 0, 0, 1.0 - norm));
 | 
			
		||||
 | 
			
		||||
		brightEffect = norm < 1.0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateReso(int width, int height)
 | 
			
		||||
	{
 | 
			
		||||
		geometry.rect.w = width;
 | 
			
		||||
		geometry.rect.h = height;
 | 
			
		||||
 | 
			
		||||
		screenQuad.setTexPosRect(geometry.rect, geometry.rect);
 | 
			
		||||
		brightnessQuad.setTexPosRect(geometry.rect, geometry.rect);
 | 
			
		||||
 | 
			
		||||
		notifyGeometryChange();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setResolution(int width, int height)
 | 
			
		||||
	{
 | 
			
		||||
		pp.resize(width, height);
 | 
			
		||||
		updateReso(width, height);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setScreenSize(int width, int height)
 | 
			
		||||
	{
 | 
			
		||||
		actW = width;
 | 
			
		||||
		actH = height;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	PingPong &getPP()
 | 
			
		||||
	{
 | 
			
		||||
		return pp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	PingPong pp;
 | 
			
		||||
	Quad screenQuad;
 | 
			
		||||
	Quad brightnessQuad;
 | 
			
		||||
	bool brightEffect;
 | 
			
		||||
	int actW, actH;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct FPSLimiter
 | 
			
		||||
{
 | 
			
		||||
	unsigned lastTickCount;
 | 
			
		||||
	unsigned mspf; /* ms per frame */
 | 
			
		||||
 | 
			
		||||
	FPSLimiter(unsigned desiredFPS)
 | 
			
		||||
	    : lastTickCount(SDL_GetTicks())
 | 
			
		||||
	{
 | 
			
		||||
		setDesiredFPS(desiredFPS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setDesiredFPS(unsigned value)
 | 
			
		||||
	{
 | 
			
		||||
		mspf = 1000 / value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void delay()
 | 
			
		||||
	{
 | 
			
		||||
		unsigned tmpTicks = SDL_GetTicks();
 | 
			
		||||
		unsigned tickDelta = tmpTicks - lastTickCount;
 | 
			
		||||
		lastTickCount = tmpTicks;
 | 
			
		||||
 | 
			
		||||
		int toDelay = mspf - tickDelta;
 | 
			
		||||
		if (toDelay < 0)
 | 
			
		||||
			toDelay = 0;
 | 
			
		||||
 | 
			
		||||
		SDL_Delay(toDelay);
 | 
			
		||||
		lastTickCount = SDL_GetTicks();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Timer
 | 
			
		||||
{
 | 
			
		||||
	uint64_t lastTicks;
 | 
			
		||||
	uint64_t acc;
 | 
			
		||||
	int counter;
 | 
			
		||||
 | 
			
		||||
	Timer()
 | 
			
		||||
	    : lastTicks(SDL_GetPerformanceCounter()),
 | 
			
		||||
	      acc(0),
 | 
			
		||||
	      counter(0)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct GraphicsPrivate
 | 
			
		||||
{
 | 
			
		||||
	/* Screen resolution */
 | 
			
		||||
	Vec2i scRes;
 | 
			
		||||
	/* Actual screen size */
 | 
			
		||||
	Vec2i scSize;
 | 
			
		||||
 | 
			
		||||
	ScreenScene screen;
 | 
			
		||||
	RGSSThreadData *threadData;
 | 
			
		||||
 | 
			
		||||
	int frameRate;
 | 
			
		||||
	int frameCount;
 | 
			
		||||
	int brightness;
 | 
			
		||||
 | 
			
		||||
	FPSLimiter fpsLimiter;
 | 
			
		||||
 | 
			
		||||
	GPUTimer gpuTimer;
 | 
			
		||||
	CPUTimer cpuTimer;
 | 
			
		||||
 | 
			
		||||
	bool frozen;
 | 
			
		||||
	TexFBO frozenScene;
 | 
			
		||||
	TexFBO currentScene;
 | 
			
		||||
	Quad screenQuad;
 | 
			
		||||
	RBFBO transBuffer;
 | 
			
		||||
 | 
			
		||||
	GraphicsPrivate()
 | 
			
		||||
	    : scRes(640, 480),
 | 
			
		||||
	      scSize(scRes),
 | 
			
		||||
	      screen(scRes.x, scRes.y),
 | 
			
		||||
	      frameRate(40),
 | 
			
		||||
	      frameCount(0),
 | 
			
		||||
	      brightness(255),
 | 
			
		||||
	      fpsLimiter(frameRate),
 | 
			
		||||
	      gpuTimer(frameRate),
 | 
			
		||||
	      cpuTimer(frameRate),
 | 
			
		||||
	      frozen(false)
 | 
			
		||||
	{
 | 
			
		||||
		TexFBO::init(frozenScene);
 | 
			
		||||
		TexFBO::allocEmpty(frozenScene, scRes.x, scRes.y);
 | 
			
		||||
		TexFBO::linkFBO(frozenScene);
 | 
			
		||||
 | 
			
		||||
		TexFBO::init(currentScene);
 | 
			
		||||
		TexFBO::allocEmpty(currentScene, scRes.x, scRes.y);
 | 
			
		||||
		TexFBO::linkFBO(currentScene);
 | 
			
		||||
 | 
			
		||||
		FloatRect screenRect(0, 0, scRes.x, scRes.y);
 | 
			
		||||
		screenQuad.setTexPosRect(screenRect, screenRect);
 | 
			
		||||
 | 
			
		||||
		RBFBO::init(transBuffer);
 | 
			
		||||
		RBFBO::allocEmpty(transBuffer, scRes.x, scRes.y);
 | 
			
		||||
		RBFBO::linkFBO(transBuffer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~GraphicsPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		TexFBO::fini(frozenScene);
 | 
			
		||||
		TexFBO::fini(currentScene);
 | 
			
		||||
 | 
			
		||||
		RBFBO::fini(transBuffer);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateScreenResoRatio()
 | 
			
		||||
	{
 | 
			
		||||
		Vec2 &ratio = gState->rtData().sizeResoRatio;
 | 
			
		||||
		ratio.x = (float) scRes.x / scSize.x;
 | 
			
		||||
		ratio.y = (float) scRes.y / scSize.y;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void checkResize()
 | 
			
		||||
	{
 | 
			
		||||
		if (threadData->windowSizeMsg.pollChange(&scSize.x, &scSize.y))
 | 
			
		||||
		{
 | 
			
		||||
			screen.setScreenSize(scSize.x, scSize.y);
 | 
			
		||||
			updateScreenResoRatio();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void shutdown()
 | 
			
		||||
	{
 | 
			
		||||
		threadData->rqTermAck = true;
 | 
			
		||||
		gState->texPool().disable();
 | 
			
		||||
 | 
			
		||||
		scriptBinding->terminate();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void swapGLBuffer()
 | 
			
		||||
	{
 | 
			
		||||
		SDL_GL_SwapWindow(threadData->window);
 | 
			
		||||
		fpsLimiter.delay();
 | 
			
		||||
 | 
			
		||||
		++frameCount;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void compositeToBuffer(FBO::ID fbo)
 | 
			
		||||
	{
 | 
			
		||||
		screen.composite();
 | 
			
		||||
		FBO::bind(fbo, FBO::Draw);
 | 
			
		||||
		FBO::blit(0, 0, 0, 0, scRes.x, scRes.y);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void blitBuffer()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::blit(0, 0, 0, 0, scRes.x, scRes.y);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void blitBufferScaled()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::blit(0, 0, scRes.x, scRes.y, 0, 0, scSize.x, scSize.y);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void blitBufferFlippedScaled()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::blit(0, 0, scRes.x, scRes.y, 0, scSize.y, scSize.x, -scSize.y);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Blits currently bound read FBO to screen (upside-down) */
 | 
			
		||||
	void blitToScreen()
 | 
			
		||||
	{
 | 
			
		||||
		FBO::unbind(FBO::Draw);
 | 
			
		||||
		blitBufferFlippedScaled();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void redrawScreen()
 | 
			
		||||
	{
 | 
			
		||||
		screen.composite();
 | 
			
		||||
		blitToScreen();
 | 
			
		||||
 | 
			
		||||
		swapGLBuffer();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Graphics::Graphics(RGSSThreadData *data)
 | 
			
		||||
{
 | 
			
		||||
	p = new GraphicsPrivate;
 | 
			
		||||
	p->threadData = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Graphics::~Graphics()
 | 
			
		||||
{
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::update()
 | 
			
		||||
{
 | 
			
		||||
	gState->checkShutdown();
 | 
			
		||||
 | 
			
		||||
//	p->cpuTimer.endTiming();
 | 
			
		||||
//	p->gpuTimer.startTiming();
 | 
			
		||||
 | 
			
		||||
	if (p->frozen)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->checkResize();
 | 
			
		||||
	p->redrawScreen();
 | 
			
		||||
 | 
			
		||||
//	p->gpuTimer.endTiming();
 | 
			
		||||
//	p->cpuTimer.startTiming();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::wait(int duration)
 | 
			
		||||
{
 | 
			
		||||
	for (int i = 0; i < duration; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		gState->checkShutdown();
 | 
			
		||||
		p->checkResize();
 | 
			
		||||
		p->redrawScreen();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::fadeout(int duration)
 | 
			
		||||
{
 | 
			
		||||
	if (p->frozen)
 | 
			
		||||
		FBO::bind(p->frozenScene.fbo, FBO::Read);
 | 
			
		||||
 | 
			
		||||
	for (int i = duration-1; i > -1; --i)
 | 
			
		||||
	{
 | 
			
		||||
		setBrightness((255.0 / duration) * i);
 | 
			
		||||
 | 
			
		||||
		if (p->frozen)
 | 
			
		||||
		{
 | 
			
		||||
			p->blitToScreen();
 | 
			
		||||
			p->swapGLBuffer();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			update();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::fadein(int duration)
 | 
			
		||||
{
 | 
			
		||||
	if (p->frozen)
 | 
			
		||||
		FBO::bind(p->frozenScene.fbo, FBO::Read);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < duration; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		setBrightness((255.0 / duration) * i);
 | 
			
		||||
 | 
			
		||||
		if (p->frozen)
 | 
			
		||||
		{
 | 
			
		||||
			p->blitToScreen();
 | 
			
		||||
			p->swapGLBuffer();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			update();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::freeze()
 | 
			
		||||
{
 | 
			
		||||
	p->frozen = true;
 | 
			
		||||
 | 
			
		||||
	gState->checkShutdown();
 | 
			
		||||
	p->checkResize();
 | 
			
		||||
 | 
			
		||||
	/* Capture scene into frozen buffer */
 | 
			
		||||
	p->compositeToBuffer(p->frozenScene.fbo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::transition(int duration,
 | 
			
		||||
                          const char *filename,
 | 
			
		||||
                          int vague)
 | 
			
		||||
{
 | 
			
		||||
	vague = bound(vague, 0, 512);
 | 
			
		||||
	Bitmap *transMap = filename ? new Bitmap(filename) : 0;
 | 
			
		||||
 | 
			
		||||
	setBrightness(255);
 | 
			
		||||
 | 
			
		||||
	/* Capture new scene */
 | 
			
		||||
	p->compositeToBuffer(p->currentScene.fbo);
 | 
			
		||||
 | 
			
		||||
	if (transMap)
 | 
			
		||||
	{
 | 
			
		||||
		TransShader &shader = gState->transShader();
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.setFrozenScene(p->frozenScene.tex);
 | 
			
		||||
		shader.setCurrentScene(p->currentScene.tex);
 | 
			
		||||
		shader.setTransMap(transMap->getGLTypes().tex);
 | 
			
		||||
		shader.setVague(vague / 512.0f);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		SimpleTransShader &shader = gState->sTransShader();
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.setFrozenScene(p->frozenScene.tex);
 | 
			
		||||
		shader.setCurrentScene(p->currentScene.tex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Tex::bindMatrix(p->scRes.x, p->scRes.y);
 | 
			
		||||
 | 
			
		||||
	glState.blendMode.pushSet(BlendNone);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < duration; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		if (p->threadData->rqTerm)
 | 
			
		||||
		{
 | 
			
		||||
			FragShader::unbind();
 | 
			
		||||
			delete transMap;
 | 
			
		||||
			p->shutdown();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const float prog = i * (1.0 / duration);
 | 
			
		||||
 | 
			
		||||
		if (transMap)
 | 
			
		||||
			gState->transShader().setProg(prog);
 | 
			
		||||
		else
 | 
			
		||||
			gState->sTransShader().setProg(prog);
 | 
			
		||||
 | 
			
		||||
		FBO::bind(p->transBuffer.fbo);
 | 
			
		||||
		glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
		p->screenQuad.draw();
 | 
			
		||||
 | 
			
		||||
		p->checkResize();
 | 
			
		||||
 | 
			
		||||
		FBO::bind(p->transBuffer.fbo, FBO::Read);
 | 
			
		||||
		p->blitToScreen();
 | 
			
		||||
 | 
			
		||||
		p->swapGLBuffer();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glState.blendMode.pop();
 | 
			
		||||
 | 
			
		||||
	FragShader::unbind();
 | 
			
		||||
 | 
			
		||||
	delete transMap;
 | 
			
		||||
 | 
			
		||||
	p->frozen = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Bitmap *Graphics::snapToBitmap()
 | 
			
		||||
{
 | 
			
		||||
	Bitmap *bitmap = new Bitmap(width(), height());
 | 
			
		||||
 | 
			
		||||
	p->compositeToBuffer(bitmap->getGLTypes().fbo);
 | 
			
		||||
 | 
			
		||||
	return bitmap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::frameReset()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Graphics::width() const
 | 
			
		||||
{
 | 
			
		||||
	return p->scRes.x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Graphics::height() const
 | 
			
		||||
{
 | 
			
		||||
	return p->scRes.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::resizeScreen(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	width = bound(width, 1, 640);
 | 
			
		||||
	height = bound(height, 1, 480);
 | 
			
		||||
 | 
			
		||||
	Vec2i size(width, height);
 | 
			
		||||
 | 
			
		||||
	if (p->scRes == size)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	gState->eThread().requestWindowResize(width, height);
 | 
			
		||||
 | 
			
		||||
	p->scRes = size;
 | 
			
		||||
 | 
			
		||||
	p->screen.setResolution(width, height);
 | 
			
		||||
 | 
			
		||||
	Tex::bind(p->frozenScene.tex);
 | 
			
		||||
	Tex::allocEmpty(width, height);
 | 
			
		||||
	Tex::bind(p->currentScene.tex);
 | 
			
		||||
	Tex::allocEmpty(width, height);
 | 
			
		||||
 | 
			
		||||
	FloatRect screenRect(0, 0, width, height);
 | 
			
		||||
	p->screenQuad.setTexPosRect(screenRect, screenRect);
 | 
			
		||||
 | 
			
		||||
	RB::bind(p->transBuffer.rb);
 | 
			
		||||
	RB::allocEmpty(width, height);
 | 
			
		||||
 | 
			
		||||
	p->updateScreenResoRatio();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#undef RET_IF_DISP
 | 
			
		||||
#define RET_IF_DISP(x)
 | 
			
		||||
 | 
			
		||||
#undef CHK_DISP
 | 
			
		||||
#define CHK_DISP
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Graphics, FrameRate, int, p->frameRate)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Graphics, Brightness, int, p->brightness)
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE(Graphics, FrameCount, int, p->frameCount)
 | 
			
		||||
 | 
			
		||||
void Graphics::setFrameRate(int value)
 | 
			
		||||
{
 | 
			
		||||
	p->frameRate = bound(value, 10, 120);
 | 
			
		||||
	p->fpsLimiter.setDesiredFPS(p->frameRate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::setBrightness(int value)
 | 
			
		||||
{
 | 
			
		||||
	value = bound(value, 0, 255);
 | 
			
		||||
 | 
			
		||||
	if (p->brightness == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->brightness = value;
 | 
			
		||||
	p->screen.setBrightness(value / 255.0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Graphics::getFullscreen() const
 | 
			
		||||
{
 | 
			
		||||
	return p->threadData->ethread->getFullscreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::setFullscreen(bool value)
 | 
			
		||||
{
 | 
			
		||||
	p->threadData->ethread->requestFullscreenMode(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Scene *Graphics::getScreen() const
 | 
			
		||||
{
 | 
			
		||||
	return &p->screen;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Graphics::repaintWait(volatile bool *exitCond)
 | 
			
		||||
{
 | 
			
		||||
	if (*exitCond)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	/* Repaint the screen with the last good frame we drew */
 | 
			
		||||
	p->screen.getPP().bindLastBuffer();
 | 
			
		||||
	FBO::unbind(FBO::Draw);
 | 
			
		||||
 | 
			
		||||
	while (!*exitCond)
 | 
			
		||||
	{
 | 
			
		||||
		gState->checkShutdown();
 | 
			
		||||
 | 
			
		||||
		p->blitBufferFlippedScaled();
 | 
			
		||||
		SDL_GL_SwapWindow(p->threadData->window);
 | 
			
		||||
		p->fpsLimiter.delay();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								src/graphics.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/graphics.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,73 @@
 | 
			
		|||
/*
 | 
			
		||||
** graphics.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef GRAPHICS_H
 | 
			
		||||
#define GRAPHICS_H
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
class Scene;
 | 
			
		||||
class Bitmap;
 | 
			
		||||
struct RGSSThreadData;
 | 
			
		||||
struct GraphicsPrivate;
 | 
			
		||||
 | 
			
		||||
class Graphics
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Graphics(RGSSThreadData *data);
 | 
			
		||||
	~Graphics();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
	void freeze();
 | 
			
		||||
	void transition(int duration = 8,
 | 
			
		||||
	                const char *filename = 0,
 | 
			
		||||
	                int vague = 40);
 | 
			
		||||
 | 
			
		||||
	void wait(int duration);
 | 
			
		||||
	void fadeout(int duration);
 | 
			
		||||
	void fadein(int duration);
 | 
			
		||||
 | 
			
		||||
	Bitmap *snapToBitmap();
 | 
			
		||||
 | 
			
		||||
	void frameReset();
 | 
			
		||||
 | 
			
		||||
	int width() const;
 | 
			
		||||
	int height() const;
 | 
			
		||||
	void resizeScreen(int width, int height);
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( FrameRate,  int )
 | 
			
		||||
	DECL_ATTR( FrameCount, int )
 | 
			
		||||
	DECL_ATTR( Brightness, int )
 | 
			
		||||
 | 
			
		||||
	/* Non-standard extension */
 | 
			
		||||
	DECL_ATTR( Fullscreen, bool )
 | 
			
		||||
 | 
			
		||||
	/* <internal> */
 | 
			
		||||
	Scene *getScreen() const;
 | 
			
		||||
	/* Repaint screen with static image until exitCond
 | 
			
		||||
	 * turns true. Used in EThread::showMessageBox() */
 | 
			
		||||
	void repaintWait(volatile bool *exitCond);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GraphicsPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // GRAPHICS_H
 | 
			
		||||
							
								
								
									
										669
									
								
								src/input.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										669
									
								
								src/input.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,669 @@
 | 
			
		|||
/*
 | 
			
		||||
** input.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "input.h"
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_scancode.h"
 | 
			
		||||
#include "SDL2/SDL_mouse.h"
 | 
			
		||||
 | 
			
		||||
#include <QVector>
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
const int Input::buttonCodeSize = 24;
 | 
			
		||||
 | 
			
		||||
struct ButtonState
 | 
			
		||||
{
 | 
			
		||||
	bool pressed;
 | 
			
		||||
	bool triggered;
 | 
			
		||||
	bool repeated;
 | 
			
		||||
 | 
			
		||||
	ButtonState()
 | 
			
		||||
		: pressed(false),
 | 
			
		||||
		  triggered(false),
 | 
			
		||||
		  repeated(false)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct KbBindingData
 | 
			
		||||
{
 | 
			
		||||
	SDL_Scancode source;
 | 
			
		||||
	Input::ButtonCode target;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct JsBindingData
 | 
			
		||||
{
 | 
			
		||||
	unsigned int      source;
 | 
			
		||||
	Input::ButtonCode target;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct Binding
 | 
			
		||||
{
 | 
			
		||||
	Binding(Input::ButtonCode target = Input::None)
 | 
			
		||||
		: target(target)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	virtual bool sourceActive() const = 0;
 | 
			
		||||
	virtual bool sourceRepeatable() const = 0;
 | 
			
		||||
 | 
			
		||||
	Input::ButtonCode target;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Keyboard binding */
 | 
			
		||||
struct KbBinding : public Binding
 | 
			
		||||
{
 | 
			
		||||
	KbBinding() {}
 | 
			
		||||
 | 
			
		||||
	KbBinding(const KbBindingData &data)
 | 
			
		||||
		: Binding(data.target),
 | 
			
		||||
		  source(data.source)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool sourceActive() const
 | 
			
		||||
	{
 | 
			
		||||
		return EventThread::keyStates[source];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool sourceRepeatable() const
 | 
			
		||||
	{
 | 
			
		||||
//		return (source >= sf::Keyboard::A    && source <= sf::Keyboard::Num9) ||
 | 
			
		||||
//			   (source >= sf::Keyboard::Left && source <= sf::Keyboard::F15);
 | 
			
		||||
		return (source >= SDL_SCANCODE_A     && source <= SDL_SCANCODE_0)    ||
 | 
			
		||||
		       (source >= SDL_SCANCODE_RIGHT && source <= SDL_SCANCODE_UP)   ||
 | 
			
		||||
		       (source >= SDL_SCANCODE_F1    && source <= SDL_SCANCODE_F12);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SDL_Scancode source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Joystick button binding */
 | 
			
		||||
struct JsButtonBinding : public Binding
 | 
			
		||||
{
 | 
			
		||||
	JsButtonBinding() {}
 | 
			
		||||
 | 
			
		||||
	JsButtonBinding(const JsBindingData &data)
 | 
			
		||||
		: Binding(data.target),
 | 
			
		||||
		  source(data.source)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool sourceActive() const
 | 
			
		||||
	{
 | 
			
		||||
		return EventThread::joyState.buttons[source];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool sourceRepeatable() const
 | 
			
		||||
	{
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	unsigned int source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Joystick axis binding */
 | 
			
		||||
struct JsAxisBinding : public Binding
 | 
			
		||||
{
 | 
			
		||||
	JsAxisBinding() {}
 | 
			
		||||
 | 
			
		||||
	JsAxisBinding(int *source,
 | 
			
		||||
	              int compareValue,
 | 
			
		||||
                  Input::ButtonCode target)
 | 
			
		||||
	    : Binding(target),
 | 
			
		||||
	      source(source),
 | 
			
		||||
	      compareValue(compareValue)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool sourceActive() const
 | 
			
		||||
	{
 | 
			
		||||
		return (*source == compareValue);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool sourceRepeatable() const
 | 
			
		||||
	{
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int *source;
 | 
			
		||||
	int compareValue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Mouse button binding */
 | 
			
		||||
struct MsBinding : public Binding
 | 
			
		||||
{
 | 
			
		||||
	MsBinding() {}
 | 
			
		||||
 | 
			
		||||
	MsBinding(int buttonIndex,
 | 
			
		||||
	          Input::ButtonCode target)
 | 
			
		||||
	    : Binding(target),
 | 
			
		||||
	      index(buttonIndex)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	bool sourceActive() const
 | 
			
		||||
	{
 | 
			
		||||
		return EventThread::mouseState.buttons[index];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool sourceRepeatable() const
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int index;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Not rebindable */
 | 
			
		||||
//static const KbBindingData staticKbBindings[] =
 | 
			
		||||
//{
 | 
			
		||||
//	{ sf::Keyboard::Left,     Input::Left  },
 | 
			
		||||
//	{ sf::Keyboard::Right,    Input::Right },
 | 
			
		||||
//	{ sf::Keyboard::Up,       Input::Up    },
 | 
			
		||||
//	{ sf::Keyboard::Down,     Input::Down  },
 | 
			
		||||
//	{ sf::Keyboard::LShift,   Input::Shift },
 | 
			
		||||
//	{ sf::Keyboard::RShift,   Input::Shift },
 | 
			
		||||
//	{ sf::Keyboard::LControl, Input::Ctrl  },
 | 
			
		||||
//	{ sf::Keyboard::RControl, Input::Ctrl  },
 | 
			
		||||
//	{ sf::Keyboard::LAlt,     Input::Alt   },
 | 
			
		||||
//	{ sf::Keyboard::RAlt,     Input::Alt   },
 | 
			
		||||
//	{ sf::Keyboard::F5,       Input::F5    },
 | 
			
		||||
//	{ sf::Keyboard::F6,       Input::F6    },
 | 
			
		||||
//	{ sf::Keyboard::F7,       Input::F7    },
 | 
			
		||||
//	{ sf::Keyboard::F8,       Input::F8    },
 | 
			
		||||
//	{ sf::Keyboard::F9,       Input::F9    }
 | 
			
		||||
//};
 | 
			
		||||
static const KbBindingData staticKbBindings[] =
 | 
			
		||||
{
 | 
			
		||||
	{ SDL_SCANCODE_LEFT,   Input::Left  },
 | 
			
		||||
	{ SDL_SCANCODE_RIGHT,  Input::Right },
 | 
			
		||||
	{ SDL_SCANCODE_UP,     Input::Up    },
 | 
			
		||||
	{ SDL_SCANCODE_DOWN,   Input::Down  },
 | 
			
		||||
	{ SDL_SCANCODE_LSHIFT, Input::Shift },
 | 
			
		||||
	{ SDL_SCANCODE_RSHIFT, Input::Shift },
 | 
			
		||||
	{ SDL_SCANCODE_LCTRL,  Input::Ctrl  },
 | 
			
		||||
	{ SDL_SCANCODE_RCTRL,  Input::Ctrl  },
 | 
			
		||||
	{ SDL_SCANCODE_LALT,   Input::Alt   },
 | 
			
		||||
	{ SDL_SCANCODE_RALT,   Input::Alt   },
 | 
			
		||||
	{ SDL_SCANCODE_F5,     Input::F5    },
 | 
			
		||||
	{ SDL_SCANCODE_F6,     Input::F6    },
 | 
			
		||||
	{ SDL_SCANCODE_F7,     Input::F7    },
 | 
			
		||||
	{ SDL_SCANCODE_F8,     Input::F8    },
 | 
			
		||||
	{ SDL_SCANCODE_F9,     Input::F9    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(staticKbBindings);
 | 
			
		||||
 | 
			
		||||
/* Rebindable */
 | 
			
		||||
//static const KbBindingData defaultKbBindings[] =
 | 
			
		||||
//{
 | 
			
		||||
//	{ sf::Keyboard::Space,  Input::C    },
 | 
			
		||||
//	{ sf::Keyboard::Return, Input::C    },
 | 
			
		||||
//	{ sf::Keyboard::Escape, Input::B    },
 | 
			
		||||
//	{ sf::Keyboard::Num0,   Input::B    },
 | 
			
		||||
//	{ sf::Keyboard::LShift, Input::A    },
 | 
			
		||||
//	{ sf::Keyboard::RShift, Input::A    },
 | 
			
		||||
//	{ sf::Keyboard::Z,      Input::A    },
 | 
			
		||||
//	{ sf::Keyboard::X,      Input::B    },
 | 
			
		||||
//	{ sf::Keyboard::C,      Input::C    },
 | 
			
		||||
//	{ sf::Keyboard::V,      Input::None },
 | 
			
		||||
//	{ sf::Keyboard::B,      Input::None },
 | 
			
		||||
//	{ sf::Keyboard::A,      Input::X    },
 | 
			
		||||
//	{ sf::Keyboard::S,      Input::Y    },
 | 
			
		||||
//	{ sf::Keyboard::D,      Input::Z    },
 | 
			
		||||
//	{ sf::Keyboard::Q,      Input::L    },
 | 
			
		||||
//	{ sf::Keyboard::W,      Input::R    }
 | 
			
		||||
//};
 | 
			
		||||
static const KbBindingData defaultKbBindings[] =
 | 
			
		||||
{
 | 
			
		||||
	{ SDL_SCANCODE_SPACE,  Input::C    },
 | 
			
		||||
	{ SDL_SCANCODE_RETURN, Input::C    },
 | 
			
		||||
	{ SDL_SCANCODE_ESCAPE, Input::B    },
 | 
			
		||||
	{ SDL_SCANCODE_KP_0,   Input::B    },
 | 
			
		||||
	{ SDL_SCANCODE_LSHIFT, Input::A    },
 | 
			
		||||
	{ SDL_SCANCODE_RSHIFT, Input::A    },
 | 
			
		||||
	{ SDL_SCANCODE_Z,      Input::A    },
 | 
			
		||||
	{ SDL_SCANCODE_X,      Input::B    },
 | 
			
		||||
	{ SDL_SCANCODE_C,      Input::C    },
 | 
			
		||||
	{ SDL_SCANCODE_V,      Input::None },
 | 
			
		||||
	{ SDL_SCANCODE_B,      Input::None },
 | 
			
		||||
	{ SDL_SCANCODE_S,      Input::X    },
 | 
			
		||||
	{ SDL_SCANCODE_A,      Input::Y    },
 | 
			
		||||
	{ SDL_SCANCODE_D,      Input::Z    },
 | 
			
		||||
	{ SDL_SCANCODE_Q,      Input::L    },
 | 
			
		||||
	{ SDL_SCANCODE_W,      Input::R    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(defaultKbBindings);
 | 
			
		||||
 | 
			
		||||
/* Rebindable */
 | 
			
		||||
static const JsBindingData defaultJsBindings[] =
 | 
			
		||||
{
 | 
			
		||||
	{ 0, Input::A    },
 | 
			
		||||
	{ 1, Input::B    },
 | 
			
		||||
	{ 2, Input::C    },
 | 
			
		||||
	{ 3, Input::X    },
 | 
			
		||||
	{ 4, Input::Y    },
 | 
			
		||||
	{ 5, Input::Z    },
 | 
			
		||||
	{ 6, Input::L    },
 | 
			
		||||
	{ 7, Input::R    },
 | 
			
		||||
	{ 8, Input::None },
 | 
			
		||||
	{ 9, Input::None }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(defaultJsBindings);
 | 
			
		||||
 | 
			
		||||
static const int mapToIndex[] =
 | 
			
		||||
{
 | 
			
		||||
	0, 0,
 | 
			
		||||
	1, 0, 2, 0, 3, 0, 4, 0,
 | 
			
		||||
	0,
 | 
			
		||||
	5, 6, 7, 8, 9, 10, 11, 12,
 | 
			
		||||
	0, 0,
 | 
			
		||||
	13, 14, 15,
 | 
			
		||||
	0,
 | 
			
		||||
	16, 17, 18, 19, 20,
 | 
			
		||||
    0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    21, 22, 23
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(mapToIndex);
 | 
			
		||||
 | 
			
		||||
static const Input::ButtonCode dirs[] =
 | 
			
		||||
{ Input::Down, Input::Left, Input::Right, Input::Up };
 | 
			
		||||
 | 
			
		||||
static const int dirFlags[] =
 | 
			
		||||
{
 | 
			
		||||
    1 << Input::Down,
 | 
			
		||||
    1 << Input::Left,
 | 
			
		||||
    1 << Input::Right,
 | 
			
		||||
    1 << Input::Up
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Dir4 is always zero on these combinations */
 | 
			
		||||
static const int deadDirFlags[] =
 | 
			
		||||
{
 | 
			
		||||
    dirFlags[0] | dirFlags[3],
 | 
			
		||||
    dirFlags[1] | dirFlags[2]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const Input::ButtonCode otherDirs[4][3] =
 | 
			
		||||
{
 | 
			
		||||
	{ Input::Left, Input::Right, Input::Up    }, // Down
 | 
			
		||||
	{ Input::Down, Input::Up,    Input::Right }, // Left
 | 
			
		||||
	{ Input::Down, Input::Up,    Input::Left  }, // Right
 | 
			
		||||
	{ Input::Left, Input::Right, Input::Up    }  // Up
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct InputPrivate
 | 
			
		||||
{
 | 
			
		||||
	QVector<KbBinding> kbBindings;
 | 
			
		||||
	QVector<JsAxisBinding> jsABindings;
 | 
			
		||||
	QVector<JsButtonBinding> jsBBindings;
 | 
			
		||||
	QVector<MsBinding> msBindings;
 | 
			
		||||
 | 
			
		||||
	/* Collective binding array */
 | 
			
		||||
	QVector<Binding*> bindings;
 | 
			
		||||
 | 
			
		||||
	ButtonState *states;
 | 
			
		||||
	ButtonState *statesOld;
 | 
			
		||||
 | 
			
		||||
	Input::ButtonCode repeating;
 | 
			
		||||
	unsigned int repeatCount;
 | 
			
		||||
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		int active;
 | 
			
		||||
		Input::ButtonCode previous;
 | 
			
		||||
	} dir4Data;
 | 
			
		||||
 | 
			
		||||
	struct
 | 
			
		||||
	{
 | 
			
		||||
		int active;
 | 
			
		||||
	} dir8Data;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	InputPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		initKbBindings();
 | 
			
		||||
		initJsBindings();
 | 
			
		||||
		initMsBindings();
 | 
			
		||||
 | 
			
		||||
		states    = new ButtonState[Input::buttonCodeSize];
 | 
			
		||||
		statesOld = new ButtonState[Input::buttonCodeSize];
 | 
			
		||||
 | 
			
		||||
		// Clear buffers
 | 
			
		||||
		clearBuffer();
 | 
			
		||||
		swapBuffers();
 | 
			
		||||
		clearBuffer();
 | 
			
		||||
 | 
			
		||||
		repeating = Input::None;
 | 
			
		||||
		repeatCount = 0;
 | 
			
		||||
 | 
			
		||||
		dir4Data.active = 0;
 | 
			
		||||
		dir4Data.previous = Input::None;
 | 
			
		||||
 | 
			
		||||
		dir8Data.active = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~InputPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		delete states;
 | 
			
		||||
		delete statesOld;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline ButtonState &getStateCheck(int code)
 | 
			
		||||
	{
 | 
			
		||||
		int index;
 | 
			
		||||
 | 
			
		||||
		if (code < 0 || code > mapToIndexN-1)
 | 
			
		||||
			index = 0;
 | 
			
		||||
		else
 | 
			
		||||
			index = mapToIndex[code];
 | 
			
		||||
 | 
			
		||||
		return states[index];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline ButtonState &getState(Input::ButtonCode code)
 | 
			
		||||
	{
 | 
			
		||||
		return states[mapToIndex[code]];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline ButtonState &getOldState(Input::ButtonCode code)
 | 
			
		||||
	{
 | 
			
		||||
		return statesOld[mapToIndex[code]];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void swapBuffers()
 | 
			
		||||
	{
 | 
			
		||||
		ButtonState *tmp = states;
 | 
			
		||||
		states = statesOld;
 | 
			
		||||
		statesOld = tmp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void clearBuffer()
 | 
			
		||||
	{
 | 
			
		||||
		static int size = sizeof(ButtonState) * Input::buttonCodeSize;
 | 
			
		||||
		memset(states, 0, size);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void initKbBindings()
 | 
			
		||||
	{
 | 
			
		||||
		kbBindings.resize(staticKbBindingsN+defaultKbBindingsN);
 | 
			
		||||
 | 
			
		||||
		int n = 0;
 | 
			
		||||
		for (int i = 0; i < staticKbBindingsN; ++i)
 | 
			
		||||
			kbBindings[n++] = KbBinding(staticKbBindings[i]);
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < defaultKbBindingsN; ++i)
 | 
			
		||||
			kbBindings[n++] = KbBinding(defaultKbBindings[i]);
 | 
			
		||||
 | 
			
		||||
		/* Add to binging array */
 | 
			
		||||
		for (int i = 0; i < kbBindings.count(); ++i)
 | 
			
		||||
			bindings.append(&kbBindings[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void initJsBindings()
 | 
			
		||||
	{
 | 
			
		||||
		/* Create axis bindings */
 | 
			
		||||
		jsABindings.resize(4);
 | 
			
		||||
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis,  0x7FFF, Input::Right);
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.xAxis, -0x8000, Input::Left);
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis,  0x7FFF, Input::Down);
 | 
			
		||||
		jsABindings[i++] = JsAxisBinding(&EventThread::joyState.yAxis, -0x8000, Input::Up);
 | 
			
		||||
 | 
			
		||||
		/* Create button bindings */
 | 
			
		||||
		jsBBindings.resize(defaultJsBindingsN);
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < defaultJsBindingsN; ++i)
 | 
			
		||||
			jsBBindings[i] = JsButtonBinding(defaultJsBindings[i]);
 | 
			
		||||
 | 
			
		||||
		/* Add to binging array */
 | 
			
		||||
		for (int i = 0; i < jsABindings.count(); ++i)
 | 
			
		||||
			bindings.append(&jsABindings[i]);
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < jsBBindings.count(); ++i)
 | 
			
		||||
			bindings.append(&jsBBindings[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void initMsBindings()
 | 
			
		||||
	{
 | 
			
		||||
		msBindings.resize(3);
 | 
			
		||||
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		msBindings[i++] = MsBinding(SDL_BUTTON_LEFT,   Input::MouseLeft);
 | 
			
		||||
		msBindings[i++] = MsBinding(SDL_BUTTON_MIDDLE, Input::MouseMiddle);
 | 
			
		||||
		msBindings[i++] = MsBinding(SDL_BUTTON_RIGHT,  Input::MouseRight);
 | 
			
		||||
 | 
			
		||||
		/* Add to binding array */
 | 
			
		||||
		for (int i = 0; i < msBindings.count(); ++i)
 | 
			
		||||
			bindings.append(&msBindings[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void pollBindings(Input::ButtonCode &repeatCand)
 | 
			
		||||
	{
 | 
			
		||||
		Q_FOREACH (const Binding *b, bindings)
 | 
			
		||||
			pollBindingPriv(*b, repeatCand);
 | 
			
		||||
 | 
			
		||||
		updateDir4();
 | 
			
		||||
		updateDir8();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void pollBindingPriv(const Binding &b,
 | 
			
		||||
						 Input::ButtonCode &repeatCand)
 | 
			
		||||
	{	
 | 
			
		||||
		if (!b.sourceActive())
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (b.target == Input::None)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		ButtonState &state = getState(b.target);
 | 
			
		||||
		ButtonState &oldState = getOldState(b.target);
 | 
			
		||||
 | 
			
		||||
		state.pressed = true;
 | 
			
		||||
 | 
			
		||||
		/* Must have been released before to trigger */
 | 
			
		||||
		if (!oldState.pressed)
 | 
			
		||||
			state.triggered = true;
 | 
			
		||||
 | 
			
		||||
		/* Unbound keys don't create/break repeat */
 | 
			
		||||
		if (repeatCand != Input::None)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (repeating != b.target &&
 | 
			
		||||
			!oldState.pressed)
 | 
			
		||||
		{
 | 
			
		||||
			if (b.sourceRepeatable())
 | 
			
		||||
				repeatCand = b.target;
 | 
			
		||||
			else
 | 
			
		||||
				/* Unrepeatable keys still break current repeat */
 | 
			
		||||
				repeating = Input::None;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateDir4()
 | 
			
		||||
	{
 | 
			
		||||
		int dirFlag = 0;
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < 4; ++i)
 | 
			
		||||
			dirFlag |= (getState(dirs[i]).pressed ? dirFlags[i] : 0);
 | 
			
		||||
 | 
			
		||||
		if (dirFlag == deadDirFlags[0] || dirFlag == deadDirFlags[1])
 | 
			
		||||
		{
 | 
			
		||||
			dir4Data.active = Input::None;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (dir4Data.previous != Input::None)
 | 
			
		||||
		{
 | 
			
		||||
			/* Check if prev still pressed */
 | 
			
		||||
			if (getState(dir4Data.previous).pressed)
 | 
			
		||||
			{
 | 
			
		||||
				for (int i = 0; i < 3; ++i)
 | 
			
		||||
				{
 | 
			
		||||
					Input::ButtonCode other =
 | 
			
		||||
							otherDirs[(dir4Data.previous/2)-1][i];
 | 
			
		||||
 | 
			
		||||
					if (!getState(other).pressed)
 | 
			
		||||
						continue;
 | 
			
		||||
 | 
			
		||||
					dir4Data.active = other;
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < 4; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			if (!getState(dirs[i]).pressed)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			dir4Data.active = dirs[i];
 | 
			
		||||
			dir4Data.previous = dirs[i];
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		dir4Data.active   = Input::None;
 | 
			
		||||
		dir4Data.previous = Input::None;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateDir8()
 | 
			
		||||
	{
 | 
			
		||||
		static const int combos[4][4] =
 | 
			
		||||
		{
 | 
			
		||||
			{ 2, 1, 3, 0 },
 | 
			
		||||
			{ 1, 4, 0, 7 },
 | 
			
		||||
			{ 3, 0, 6, 9 },
 | 
			
		||||
			{ 0, 7, 9, 8 }
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		dir8Data.active = 0;
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < 4; ++i)
 | 
			
		||||
		{
 | 
			
		||||
			Input::ButtonCode one = dirs[i];
 | 
			
		||||
 | 
			
		||||
			if (!getState(one).pressed)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			for (int j = 0; j < 3; ++j)
 | 
			
		||||
			{
 | 
			
		||||
				Input::ButtonCode other = otherDirs[i][j];
 | 
			
		||||
 | 
			
		||||
				if (!getState(other).pressed)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
				dir8Data.active = combos[(one/2)-1][(other/2)-1];
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			dir8Data.active = one;
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Input::Input()
 | 
			
		||||
{
 | 
			
		||||
	p = new InputPrivate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Input::update()
 | 
			
		||||
{
 | 
			
		||||
	gState->checkShutdown();
 | 
			
		||||
 | 
			
		||||
	p->swapBuffers();
 | 
			
		||||
	p->clearBuffer();
 | 
			
		||||
 | 
			
		||||
	ButtonCode repeatCand = None;
 | 
			
		||||
 | 
			
		||||
	/* Poll all bindings */
 | 
			
		||||
	p->pollBindings(repeatCand);
 | 
			
		||||
 | 
			
		||||
	/* Check for new repeating key */
 | 
			
		||||
	if (repeatCand != None && repeatCand != p->repeating)
 | 
			
		||||
	{
 | 
			
		||||
		p->repeating = repeatCand;
 | 
			
		||||
		p->repeatCount = 0;
 | 
			
		||||
		p->getState(repeatCand).repeated = true;
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check if repeating key is still pressed */
 | 
			
		||||
	if (p->getState(p->repeating).pressed)
 | 
			
		||||
	{
 | 
			
		||||
		p->repeatCount++;
 | 
			
		||||
 | 
			
		||||
		/* Repeatsequence is [r...............(r...)+] */
 | 
			
		||||
		if (p->repeatCount > 15 && ((p->repeatCount % 4) == 0))
 | 
			
		||||
			p->getState(p->repeating).repeated = true;
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p->repeating = None;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Input::isPressed(int button)
 | 
			
		||||
{
 | 
			
		||||
	return p->getStateCheck(button).pressed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Input::isTriggered(int button)
 | 
			
		||||
{
 | 
			
		||||
	return p->getStateCheck(button).triggered;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Input::isRepeated(int button)
 | 
			
		||||
{
 | 
			
		||||
	return p->getStateCheck(button).repeated;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Input::dir4Value()
 | 
			
		||||
{
 | 
			
		||||
	return p->dir4Data.active;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Input::dir8Value()
 | 
			
		||||
{
 | 
			
		||||
	return p->dir8Data.active;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Input::mouseX()
 | 
			
		||||
{
 | 
			
		||||
	return EventThread::mouseState.x * gState->rtData().sizeResoRatio.x;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int Input::mouseY()
 | 
			
		||||
{
 | 
			
		||||
	return EventThread::mouseState.y * gState->rtData().sizeResoRatio.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Input::~Input()
 | 
			
		||||
{
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								src/input.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/input.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,70 @@
 | 
			
		|||
/*
 | 
			
		||||
** input.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef INPUT_H
 | 
			
		||||
#define INPUT_H
 | 
			
		||||
 | 
			
		||||
struct InputPrivate;
 | 
			
		||||
 | 
			
		||||
class Input
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	enum ButtonCode
 | 
			
		||||
	{
 | 
			
		||||
		None = 0,
 | 
			
		||||
 | 
			
		||||
		Down = 2, Left = 4, Right = 6, Up = 8,
 | 
			
		||||
 | 
			
		||||
		A = 11, B = 12, C = 13,
 | 
			
		||||
		X = 14, Y = 15, Z = 16,
 | 
			
		||||
		L = 17, R = 18,
 | 
			
		||||
 | 
			
		||||
		Shift = 21, Ctrl = 22, Alt = 23,
 | 
			
		||||
 | 
			
		||||
		F5 = 25, F6 = 26, F7 = 27, F8 = 28, F9 = 29,
 | 
			
		||||
 | 
			
		||||
		/* Non-standard extensions */
 | 
			
		||||
		MouseLeft = 38, MouseMiddle = 39, MouseRight = 40
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	static const int buttonCodeSize;
 | 
			
		||||
 | 
			
		||||
	Input();
 | 
			
		||||
	~Input();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
 | 
			
		||||
	bool isPressed(int button);
 | 
			
		||||
	bool isTriggered(int button);
 | 
			
		||||
	bool isRepeated(int button);
 | 
			
		||||
 | 
			
		||||
	int dir4Value();
 | 
			
		||||
	int dir8Value();
 | 
			
		||||
 | 
			
		||||
	/* Non-standard extensions */
 | 
			
		||||
	int mouseX();
 | 
			
		||||
	int mouseY();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	InputPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INPUT_H
 | 
			
		||||
							
								
								
									
										138
									
								
								src/intrulist.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								src/intrulist.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,138 @@
 | 
			
		|||
/*
 | 
			
		||||
** intrulist.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef INTRULIST_H
 | 
			
		||||
#define INTRULIST_H
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct IntruListLink
 | 
			
		||||
{
 | 
			
		||||
	IntruListLink<T> *prev;
 | 
			
		||||
	IntruListLink<T> *next;
 | 
			
		||||
	T *data;
 | 
			
		||||
 | 
			
		||||
	IntruListLink(T *data)
 | 
			
		||||
	    : prev(0),
 | 
			
		||||
	      next(0),
 | 
			
		||||
	      data(data)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	~IntruListLink()
 | 
			
		||||
	{
 | 
			
		||||
		if (prev && next)
 | 
			
		||||
		{
 | 
			
		||||
			next->prev = prev;
 | 
			
		||||
			prev->next = next;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
class IntruList
 | 
			
		||||
{
 | 
			
		||||
	IntruListLink<T> root;
 | 
			
		||||
	int size;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	IntruList()
 | 
			
		||||
	    : root(0),
 | 
			
		||||
	      size(0)
 | 
			
		||||
	{
 | 
			
		||||
		root.prev = &root;
 | 
			
		||||
		root.next = &root;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void prepend(IntruListLink<T> &node)
 | 
			
		||||
	{
 | 
			
		||||
		root.next->prev = &node;
 | 
			
		||||
		node.prev = &root;
 | 
			
		||||
		node.next = root.next;
 | 
			
		||||
		root.next = &node;
 | 
			
		||||
 | 
			
		||||
		size++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void append(IntruListLink<T> &node)
 | 
			
		||||
	{
 | 
			
		||||
		root.prev->next = &node;
 | 
			
		||||
		node.next = &root;
 | 
			
		||||
		node.prev = root.prev;
 | 
			
		||||
		root.prev = &node;
 | 
			
		||||
 | 
			
		||||
		size++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void insertBefore(IntruListLink<T> &node,
 | 
			
		||||
	                  IntruListLink<T> &prev)
 | 
			
		||||
	{
 | 
			
		||||
		node.next = &prev;
 | 
			
		||||
		node.prev = prev.prev;
 | 
			
		||||
		prev.prev->next = &node;
 | 
			
		||||
		prev.prev = &node;
 | 
			
		||||
 | 
			
		||||
		size++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void remove(IntruListLink<T> &node)
 | 
			
		||||
	{
 | 
			
		||||
		if (!node.next)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		node.prev->next = node.next;
 | 
			
		||||
		node.next->prev = node.prev;
 | 
			
		||||
 | 
			
		||||
		node.prev = 0;
 | 
			
		||||
		node.next = 0;
 | 
			
		||||
 | 
			
		||||
		size--;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	T *tail() const
 | 
			
		||||
	{
 | 
			
		||||
		IntruListLink<T> *node = root.prev;
 | 
			
		||||
		if (node == &root)
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
		return node->data;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	IntruListLink<T> *begin()
 | 
			
		||||
	{
 | 
			
		||||
		return root.next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	IntruListLink<T> *end()
 | 
			
		||||
	{
 | 
			
		||||
		return &root;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool isEmpty() const
 | 
			
		||||
	{
 | 
			
		||||
		return root.next == &root;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int getSize() const
 | 
			
		||||
	{
 | 
			
		||||
		return size;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // INTRULIST_H
 | 
			
		||||
							
								
								
									
										209
									
								
								src/main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								src/main.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,209 @@
 | 
			
		|||
/*
 | 
			
		||||
** main.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "GL/glew.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL.h"
 | 
			
		||||
#include "SDL2/SDL_image.h"
 | 
			
		||||
#include "SDL2/SDL_ttf.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "eventthread.h"
 | 
			
		||||
#include "debuglogger.h"
 | 
			
		||||
 | 
			
		||||
#include "binding.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
static const char *reqExt[] =
 | 
			
		||||
{
 | 
			
		||||
    "GL_ARB_fragment_program",
 | 
			
		||||
    "GL_ARB_fragment_shader",
 | 
			
		||||
    "GL_ARB_framebuffer_object",
 | 
			
		||||
    "GL_ARB_imaging",
 | 
			
		||||
    "GL_ARB_shader_objects",
 | 
			
		||||
    "GL_ARB_shading_language_100",
 | 
			
		||||
    "GL_ARB_texture_non_power_of_two",
 | 
			
		||||
    "GL_ARB_vertex_array_object",
 | 
			
		||||
    "GL_ARB_vertex_buffer_object",
 | 
			
		||||
    "GL_EXT_bgra",
 | 
			
		||||
    "GL_EXT_blend_func_separate",
 | 
			
		||||
    "GL_EXT_blend_subtract",
 | 
			
		||||
    "GL_EXT_framebuffer_blit",
 | 
			
		||||
    0
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int rgssThreadFun(void *userdata)
 | 
			
		||||
{
 | 
			
		||||
	RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata);
 | 
			
		||||
	SDL_Window *win = threadData->window;
 | 
			
		||||
	SDL_GLContext ctx;
 | 
			
		||||
 | 
			
		||||
	/* Setup GL context */
 | 
			
		||||
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 | 
			
		||||
 | 
			
		||||
	if (threadData->config.debugMode)
 | 
			
		||||
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
 | 
			
		||||
 | 
			
		||||
	ctx = SDL_GL_CreateContext(win);
 | 
			
		||||
 | 
			
		||||
	if (!ctx)
 | 
			
		||||
	{
 | 
			
		||||
		threadData->rgssErrorMsg =
 | 
			
		||||
		        QByteArray("Error creating context: ") + SDL_GetError();
 | 
			
		||||
		threadData->ethread->requestTerminate();
 | 
			
		||||
		threadData->rqTermAck = true;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (glewInit() != GLEW_OK)
 | 
			
		||||
	{
 | 
			
		||||
		threadData->rgssErrorMsg = "Error initializing glew";
 | 
			
		||||
		SDL_GL_DeleteContext(ctx);
 | 
			
		||||
		threadData->ethread->requestTerminate();
 | 
			
		||||
		threadData->rqTermAck = true;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check for required GL extensions */
 | 
			
		||||
	const char **ext = reqExt;
 | 
			
		||||
	for (int i = 0; ext[i]; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		if (!glewIsSupported(ext[i]))
 | 
			
		||||
		{
 | 
			
		||||
			threadData->rgssErrorMsg =
 | 
			
		||||
			        QByteArray("Required GL extension \"") + ext[i] + "\" not present";
 | 
			
		||||
			threadData->ethread->requestTerminate();
 | 
			
		||||
			threadData->rqTermAck = true;
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SDL_GL_SetSwapInterval(threadData->config.vsync ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
	glEnable(GL_BLEND);
 | 
			
		||||
	glDisable(GL_DEPTH_TEST);
 | 
			
		||||
 | 
			
		||||
	DebugLogger dLogger;
 | 
			
		||||
 | 
			
		||||
	GlobalState::initInstance(threadData);
 | 
			
		||||
 | 
			
		||||
	/* Start script execution */
 | 
			
		||||
	scriptBinding->execute();
 | 
			
		||||
 | 
			
		||||
	threadData->ethread->requestTerminate();
 | 
			
		||||
 | 
			
		||||
	GlobalState::finiInstance();
 | 
			
		||||
 | 
			
		||||
	SDL_GL_DeleteContext(ctx);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
	Config conf;
 | 
			
		||||
 | 
			
		||||
	conf.read();
 | 
			
		||||
	conf.readGameINI();
 | 
			
		||||
 | 
			
		||||
	if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0)
 | 
			
		||||
	{
 | 
			
		||||
		qDebug() << "Error initializing SDL:" << SDL_GetError();
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
 | 
			
		||||
	TTF_Init();
 | 
			
		||||
 | 
			
		||||
	SDL_SetHint("SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS", "0");
 | 
			
		||||
 | 
			
		||||
	SDL_Window *win;
 | 
			
		||||
	Uint32 winFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
 | 
			
		||||
 | 
			
		||||
	if (conf.winResizable)
 | 
			
		||||
		winFlags |= SDL_WINDOW_RESIZABLE;
 | 
			
		||||
	if (conf.fullscreen)
 | 
			
		||||
		winFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 | 
			
		||||
 | 
			
		||||
	win = SDL_CreateWindow(conf.game.title.constData(),
 | 
			
		||||
	                       SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
 | 
			
		||||
	                       conf.defScreenW, conf.defScreenH, winFlags);
 | 
			
		||||
 | 
			
		||||
	if (!win)
 | 
			
		||||
	{
 | 
			
		||||
		qDebug() << "Error creating window";
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	EventThread eventThread;
 | 
			
		||||
	RGSSThreadData rtData(&eventThread, argv[0], win);
 | 
			
		||||
	rtData.config = conf;
 | 
			
		||||
 | 
			
		||||
	/* Start RGSS thread */
 | 
			
		||||
	SDL_Thread *rgssThread =
 | 
			
		||||
	        SDL_CreateThread(rgssThreadFun, "rgss", &rtData);
 | 
			
		||||
 | 
			
		||||
	/* Start event processing */
 | 
			
		||||
	eventThread.process(rtData);
 | 
			
		||||
 | 
			
		||||
	/* Request RGSS thread to stop */
 | 
			
		||||
	rtData.rqTerm = true;
 | 
			
		||||
 | 
			
		||||
	/* Wait for RGSS thread response */
 | 
			
		||||
	for (int i = 0; i < 1000; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		/* We can stop waiting when the request was ack'd */
 | 
			
		||||
		if (rtData.rqTermAck)
 | 
			
		||||
		{
 | 
			
		||||
			qDebug() << "RGSS thread ack'd request after" << i*10 << "ms";
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Give RGSS thread some time to respond */
 | 
			
		||||
		SDL_Delay(10);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If RGSS thread ack'd request, wait for it to shutdown,
 | 
			
		||||
	 * otherwise abandon hope and just end the process as is. */
 | 
			
		||||
	if (rtData.rqTermAck)
 | 
			
		||||
		SDL_WaitThread(rgssThread, 0);
 | 
			
		||||
	else
 | 
			
		||||
		SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.constData(),
 | 
			
		||||
		                         "The RGSS script seems to be stuck and mkxp will now force quit", win);
 | 
			
		||||
 | 
			
		||||
	if (!rtData.rgssErrorMsg.isEmpty())
 | 
			
		||||
		SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, conf.game.title.constData(),
 | 
			
		||||
		                         rtData.rgssErrorMsg.constData(), win);
 | 
			
		||||
 | 
			
		||||
	/* Clean up any remainin events */
 | 
			
		||||
	eventThread.cleanup();
 | 
			
		||||
 | 
			
		||||
	qDebug() << "Shutting down.";
 | 
			
		||||
 | 
			
		||||
	SDL_DestroyWindow(win);
 | 
			
		||||
 | 
			
		||||
	TTF_Quit();
 | 
			
		||||
	IMG_Quit();
 | 
			
		||||
	SDL_Quit();
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										217
									
								
								src/plane.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/plane.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,217 @@
 | 
			
		|||
/*
 | 
			
		||||
** plane.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "plane.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "bitmap.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
#include "transform.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "shader.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
 | 
			
		||||
struct PlanePrivate
 | 
			
		||||
{
 | 
			
		||||
	Bitmap *bitmap;
 | 
			
		||||
	NormValue opacity;
 | 
			
		||||
	BlendType blendType;
 | 
			
		||||
	Color *color;
 | 
			
		||||
	Tone *tone;
 | 
			
		||||
 | 
			
		||||
	int ox, oy;
 | 
			
		||||
	float zoomX, zoomY;
 | 
			
		||||
 | 
			
		||||
	Scene::Geometry sceneGeo;
 | 
			
		||||
 | 
			
		||||
	bool quadSourceDirty;
 | 
			
		||||
 | 
			
		||||
	Quad quad;
 | 
			
		||||
 | 
			
		||||
	EtcTemps tmp;
 | 
			
		||||
 | 
			
		||||
	PlanePrivate()
 | 
			
		||||
	    : bitmap(0),
 | 
			
		||||
	      opacity(255),
 | 
			
		||||
	      blendType(BlendNormal),
 | 
			
		||||
	      color(&tmp.color),
 | 
			
		||||
	      tone(&tmp.tone),
 | 
			
		||||
	      ox(0), oy(0),
 | 
			
		||||
	      zoomX(1), zoomY(1),
 | 
			
		||||
	      quadSourceDirty(false)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void updateQuadSource()
 | 
			
		||||
	{
 | 
			
		||||
		FloatRect srcRect;
 | 
			
		||||
		srcRect.x = (sceneGeo.yOrigin + ox) / zoomX;
 | 
			
		||||
		srcRect.y = (sceneGeo.xOrigin + oy) / zoomY;
 | 
			
		||||
		srcRect.w = sceneGeo.rect.w / zoomX;
 | 
			
		||||
		srcRect.h = sceneGeo.rect.h / zoomY;
 | 
			
		||||
 | 
			
		||||
		quad.setTexRect(srcRect);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Plane::Plane(Viewport *viewport)
 | 
			
		||||
    : ViewportElement(viewport)
 | 
			
		||||
{
 | 
			
		||||
	p = new PlanePrivate();
 | 
			
		||||
 | 
			
		||||
	onGeometryChange(scene->getGeometry());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DISP_CLASS_NAME "plane"
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Plane, OX,        int,   p->ox)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Plane, OY,        int,   p->oy)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Plane, ZoomX,     float, p->zoomX)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Plane, ZoomY,     float, p->zoomY)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Plane, BlendType, int,   p->blendType)
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE(Plane, Opacity, int,     p->opacity)
 | 
			
		||||
DEF_ATTR_SIMPLE(Plane, Bitmap,  Bitmap*, p->bitmap)
 | 
			
		||||
DEF_ATTR_SIMPLE(Plane, Color,   Color*,  p->color)
 | 
			
		||||
DEF_ATTR_SIMPLE(Plane, Tone,    Tone*,   p->tone)
 | 
			
		||||
 | 
			
		||||
Plane::~Plane()
 | 
			
		||||
{
 | 
			
		||||
	dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::setOX(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->ox = value;
 | 
			
		||||
	p->quadSourceDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::setOY(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->oy = value;
 | 
			
		||||
	p->quadSourceDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::setZoomX(float value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->zoomX = value;
 | 
			
		||||
	p->quadSourceDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::setZoomY(float value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->zoomY = value;
 | 
			
		||||
	p->quadSourceDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::setBlendType(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	switch (value)
 | 
			
		||||
	{
 | 
			
		||||
	default :
 | 
			
		||||
	case BlendNormal :
 | 
			
		||||
		p->blendType = BlendNormal;
 | 
			
		||||
		return;
 | 
			
		||||
	case BlendAddition :
 | 
			
		||||
		p->blendType = BlendAddition;
 | 
			
		||||
		return;
 | 
			
		||||
	case BlendSubstraction :
 | 
			
		||||
		p->blendType = BlendSubstraction;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Plane::draw()
 | 
			
		||||
{
 | 
			
		||||
	if (!p->bitmap)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (p->bitmap->isDisposed())
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (!p->opacity)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (p->quadSourceDirty)
 | 
			
		||||
	{
 | 
			
		||||
		p->updateQuadSource();
 | 
			
		||||
		p->quadSourceDirty = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (p->color->hasEffect() || p->tone->hasEffect() || p->opacity != 255)
 | 
			
		||||
	{
 | 
			
		||||
		SpriteShader &shader = gState->spriteShader();
 | 
			
		||||
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.setTone(p->tone->norm);
 | 
			
		||||
		shader.setColor(p->color->norm);
 | 
			
		||||
		shader.setFlash(Vec4());
 | 
			
		||||
		shader.setOpacity(p->opacity.norm);
 | 
			
		||||
		shader.setBushOpacity(1);
 | 
			
		||||
		shader.setBushDepth(0);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glState.blendMode.pushSet(p->blendType);
 | 
			
		||||
 | 
			
		||||
	p->bitmap->flush();
 | 
			
		||||
	p->bitmap->bindTexWithMatrix();
 | 
			
		||||
	Tex::setRepeat(true);
 | 
			
		||||
 | 
			
		||||
	p->quad.draw();
 | 
			
		||||
 | 
			
		||||
	Tex::setRepeat(false);
 | 
			
		||||
	FragShader::unbind();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::onGeometryChange(const Scene::Geometry &geo)
 | 
			
		||||
{
 | 
			
		||||
	p->quad.setPosRect(FloatRect(geo.rect));
 | 
			
		||||
 | 
			
		||||
	p->sceneGeo = geo;
 | 
			
		||||
	p->quadSourceDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plane::aboutToAccess() const
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void Plane::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
	unlink();
 | 
			
		||||
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								src/plane.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/plane.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
/*
 | 
			
		||||
** plane.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef PLANE_H
 | 
			
		||||
#define PLANE_H
 | 
			
		||||
 | 
			
		||||
#include "disposable.h"
 | 
			
		||||
#include "viewport.h"
 | 
			
		||||
 | 
			
		||||
#include "SFML/Graphics/Sprite.hpp"
 | 
			
		||||
#include "SFML/Graphics/RectangleShape.hpp"
 | 
			
		||||
 | 
			
		||||
class Bitmap;
 | 
			
		||||
struct Color;
 | 
			
		||||
struct Tone;
 | 
			
		||||
 | 
			
		||||
struct PlanePrivate;
 | 
			
		||||
 | 
			
		||||
class Plane : public ViewportElement, public Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Plane(Viewport *viewport = 0);
 | 
			
		||||
	~Plane();
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Bitmap,    Bitmap* )
 | 
			
		||||
	DECL_ATTR( OX,        int     )
 | 
			
		||||
	DECL_ATTR( OY,        int     )
 | 
			
		||||
	DECL_ATTR( ZoomX,     float   )
 | 
			
		||||
	DECL_ATTR( ZoomY,     float   )
 | 
			
		||||
	DECL_ATTR( Opacity,   int     )
 | 
			
		||||
	DECL_ATTR( BlendType, int     )
 | 
			
		||||
	DECL_ATTR( Color,     Color*  )
 | 
			
		||||
	DECL_ATTR( Tone,      Tone*   )
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	PlanePrivate *p;
 | 
			
		||||
 | 
			
		||||
	void draw();
 | 
			
		||||
	void onGeometryChange(const Scene::Geometry &);
 | 
			
		||||
	void aboutToAccess() const;
 | 
			
		||||
 | 
			
		||||
	void releaseResources();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // PLANE_H
 | 
			
		||||
							
								
								
									
										182
									
								
								src/quad.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/quad.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,182 @@
 | 
			
		|||
/*
 | 
			
		||||
** quad.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef QUAD_H
 | 
			
		||||
#define QUAD_H
 | 
			
		||||
 | 
			
		||||
#include "GL/glew.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "global-ibo.h"
 | 
			
		||||
 | 
			
		||||
struct Quad
 | 
			
		||||
{
 | 
			
		||||
	Vertex vert[4];
 | 
			
		||||
	VBO::ID vbo;
 | 
			
		||||
	VAO::ID vao;
 | 
			
		||||
	bool vboDirty;
 | 
			
		||||
 | 
			
		||||
	static void setPosRect(CVertex *vert, const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		vert[i++].pos = r.topLeft();
 | 
			
		||||
		vert[i++].pos = r.topRight();
 | 
			
		||||
		vert[i++].pos = r.bottomRight();
 | 
			
		||||
		vert[i++].pos = r.bottomLeft();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void setColor(CVertex *vert, const Vec4 &c)
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < 4; ++i)
 | 
			
		||||
			vert[i].color = c;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void setPosRect(SVertex *vert, const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		vert[i++].pos = r.topLeft();
 | 
			
		||||
		vert[i++].pos = r.topRight();
 | 
			
		||||
		vert[i++].pos = r.bottomRight();
 | 
			
		||||
		vert[i++].pos = r.bottomLeft();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void setTexRect(SVertex *vert, const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		vert[i++].texPos = r.topLeft();
 | 
			
		||||
		vert[i++].texPos = r.topRight();
 | 
			
		||||
		vert[i++].texPos = r.bottomRight();
 | 
			
		||||
		vert[i++].texPos = r.bottomLeft();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void setPosRect(Vertex *vert, const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		vert[i++].pos = r.topLeft();
 | 
			
		||||
		vert[i++].pos = r.topRight();
 | 
			
		||||
		vert[i++].pos = r.bottomRight();
 | 
			
		||||
		vert[i++].pos = r.bottomLeft();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void setTexRect(Vertex *vert, const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		vert[i++].texPos = r.topLeft();
 | 
			
		||||
		vert[i++].texPos = r.topRight();
 | 
			
		||||
		vert[i++].texPos = r.bottomRight();
 | 
			
		||||
		vert[i++].texPos = r.bottomLeft();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static int setTexPosRect(SVertex *vert, const FloatRect &tex, const FloatRect &pos)
 | 
			
		||||
	{
 | 
			
		||||
		setPosRect(vert, pos);
 | 
			
		||||
		setTexRect(vert, tex);
 | 
			
		||||
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static int setTexPosRect(Vertex *vert, const FloatRect &tex, const FloatRect &pos)
 | 
			
		||||
	{
 | 
			
		||||
		setPosRect(vert, pos);
 | 
			
		||||
		setTexRect(vert, tex);
 | 
			
		||||
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Quad()
 | 
			
		||||
	    : vbo(VBO::gen()),
 | 
			
		||||
	      vao(VAO::gen()),
 | 
			
		||||
	      vboDirty(true)
 | 
			
		||||
	{
 | 
			
		||||
		VAO::bind(vao);
 | 
			
		||||
		VBO::bind(vbo);
 | 
			
		||||
		gState->bindQuadIBO();
 | 
			
		||||
 | 
			
		||||
		glEnableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
		glEnableClientState(GL_COLOR_ARRAY);
 | 
			
		||||
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
			
		||||
 | 
			
		||||
		glColorPointer   (4, GL_FLOAT, sizeof(Vertex), Vertex::colorOffset());
 | 
			
		||||
		glVertexPointer  (2, GL_FLOAT, sizeof(Vertex), Vertex::posOffset());
 | 
			
		||||
		glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), Vertex::texPosOffset());
 | 
			
		||||
 | 
			
		||||
		VAO::unbind();
 | 
			
		||||
		VBO::unbind();
 | 
			
		||||
		IBO::unbind();
 | 
			
		||||
 | 
			
		||||
		setColor(Vec4(1, 1, 1, 1));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~Quad()
 | 
			
		||||
	{
 | 
			
		||||
		VAO::del(vao);
 | 
			
		||||
		VBO::del(vbo);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateBuffer()
 | 
			
		||||
	{
 | 
			
		||||
		VBO::bind(vbo);
 | 
			
		||||
		VBO::allocEmpty(sizeof(Vertex) * 4, GL_DYNAMIC_DRAW);
 | 
			
		||||
		VBO::uploadData(sizeof(Vertex) * 4, vert, GL_DYNAMIC_DRAW);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setPosRect(const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		setPosRect(vert, r);
 | 
			
		||||
		vboDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setTexRect(const FloatRect &r)
 | 
			
		||||
	{
 | 
			
		||||
		setTexRect(vert, r);
 | 
			
		||||
		vboDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setTexPosRect(const FloatRect &tex, const FloatRect &pos)
 | 
			
		||||
	{
 | 
			
		||||
		setTexPosRect(vert, tex, pos);
 | 
			
		||||
		vboDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setColor(const Vec4 &c)
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < 4; ++i)
 | 
			
		||||
			vert[i].color = c;
 | 
			
		||||
 | 
			
		||||
		vboDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void draw()
 | 
			
		||||
	{
 | 
			
		||||
		if (vboDirty)
 | 
			
		||||
		{
 | 
			
		||||
			updateBuffer();
 | 
			
		||||
			vboDirty = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		VAO::bind(vao);
 | 
			
		||||
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
 | 
			
		||||
		VAO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // QUAD_H
 | 
			
		||||
							
								
								
									
										173
									
								
								src/quadarray.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								src/quadarray.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,173 @@
 | 
			
		|||
/*
 | 
			
		||||
** quadarray.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef QUADARRAY_H
 | 
			
		||||
#define QUADARRAY_H
 | 
			
		||||
 | 
			
		||||
#include <QtGlobal>
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "global-ibo.h"
 | 
			
		||||
 | 
			
		||||
typedef quint32 index_t;
 | 
			
		||||
#define _GL_INDEX_TYPE GL_UNSIGNED_INT
 | 
			
		||||
 | 
			
		||||
struct ColorQuadArray
 | 
			
		||||
{
 | 
			
		||||
	QVector<Vertex> vertices;
 | 
			
		||||
 | 
			
		||||
	VBO::ID vbo;
 | 
			
		||||
	VAO::ID vao;
 | 
			
		||||
 | 
			
		||||
	int quadCount;
 | 
			
		||||
 | 
			
		||||
	ColorQuadArray()
 | 
			
		||||
	    : quadCount(0)
 | 
			
		||||
	{
 | 
			
		||||
		vbo = VBO::gen();
 | 
			
		||||
		vao = VAO::gen();
 | 
			
		||||
 | 
			
		||||
		VAO::bind(vao);
 | 
			
		||||
		VBO::bind(vbo);
 | 
			
		||||
		gState->bindQuadIBO();
 | 
			
		||||
 | 
			
		||||
		glEnableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
			
		||||
		glEnableClientState(GL_COLOR_ARRAY);
 | 
			
		||||
 | 
			
		||||
		glVertexPointer  (2, GL_FLOAT, sizeof(Vertex), Vertex::posOffset());
 | 
			
		||||
		glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), Vertex::texPosOffset());
 | 
			
		||||
		glColorPointer   (4, GL_FLOAT, sizeof(Vertex), Vertex::colorOffset());
 | 
			
		||||
 | 
			
		||||
		VAO::unbind();
 | 
			
		||||
		IBO::unbind();
 | 
			
		||||
		VBO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~ColorQuadArray()
 | 
			
		||||
	{
 | 
			
		||||
		VBO::del(vbo);
 | 
			
		||||
		VAO::del(vao);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void resize(int size)
 | 
			
		||||
	{
 | 
			
		||||
		vertices.resize(size * 4);
 | 
			
		||||
		quadCount = size;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* This needs to be called after the final 'append()' call
 | 
			
		||||
	 * and previous to the first 'draw()' call. */
 | 
			
		||||
	void commit()
 | 
			
		||||
	{
 | 
			
		||||
		VBO::bind(vbo);
 | 
			
		||||
		VBO::uploadData(vertices.size() * sizeof(Vertex), vertices.constData(), GL_DYNAMIC_DRAW);
 | 
			
		||||
		VBO::unbind();
 | 
			
		||||
 | 
			
		||||
		gState->ensureQuadIBO(quadCount);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void draw(uint offset, uint count)
 | 
			
		||||
	{
 | 
			
		||||
		VAO::bind(vao);
 | 
			
		||||
 | 
			
		||||
		const char *_offset = (const char*) 0 + offset * 6 * sizeof(index_t);
 | 
			
		||||
		glDrawElements(GL_TRIANGLES, count * 6, _GL_INDEX_TYPE, _offset);
 | 
			
		||||
 | 
			
		||||
		VAO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void draw()
 | 
			
		||||
	{
 | 
			
		||||
		draw(0, quadCount);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int count() const
 | 
			
		||||
	{
 | 
			
		||||
		return quadCount;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PointArray
 | 
			
		||||
{
 | 
			
		||||
	QVector<Vertex> vertices;
 | 
			
		||||
	VBO::ID vbo;
 | 
			
		||||
	VAO::ID vao;
 | 
			
		||||
 | 
			
		||||
	PointArray()
 | 
			
		||||
	{
 | 
			
		||||
		vbo = VBO::gen();
 | 
			
		||||
		vao = VAO::gen();
 | 
			
		||||
 | 
			
		||||
		VAO::bind(vao);
 | 
			
		||||
		VBO::bind(vbo);
 | 
			
		||||
 | 
			
		||||
		glEnableClientState(GL_VERTEX_ARRAY);
 | 
			
		||||
		glEnableClientState(GL_COLOR_ARRAY);
 | 
			
		||||
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
			
		||||
 | 
			
		||||
		glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (const GLvoid*) 0);
 | 
			
		||||
		glColorPointer (4, GL_FLOAT, sizeof(Vertex), (const GLvoid*) sizeof(SVertex));
 | 
			
		||||
 | 
			
		||||
		VAO::unbind();
 | 
			
		||||
		VBO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~PointArray()
 | 
			
		||||
	{
 | 
			
		||||
		VBO::del(vbo);
 | 
			
		||||
		VAO::del(vao);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void append(const Vec2 &pos, const Vec4 &color)
 | 
			
		||||
	{
 | 
			
		||||
		Vertex vert;
 | 
			
		||||
		vert.pos = pos;
 | 
			
		||||
		vert.color = color;
 | 
			
		||||
		vertices.append(vert);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void commit()
 | 
			
		||||
	{
 | 
			
		||||
		VBO::bind(vbo);
 | 
			
		||||
		VBO::uploadData(vertices.size() * sizeof(Vertex), vertices.constData());
 | 
			
		||||
		VBO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void reset()
 | 
			
		||||
	{
 | 
			
		||||
		vertices.clear();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void draw()
 | 
			
		||||
	{
 | 
			
		||||
		VAO::bind(vao);
 | 
			
		||||
		glDrawArrays(GL_POINTS, 0, count());
 | 
			
		||||
		VAO::unbind();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	int count()
 | 
			
		||||
	{
 | 
			
		||||
		return vertices.count();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // QUADARRAY_H
 | 
			
		||||
							
								
								
									
										146
									
								
								src/scene.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								src/scene.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,146 @@
 | 
			
		|||
/*
 | 
			
		||||
** scene.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "scene.h"
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
Scene::Scene()
 | 
			
		||||
{
 | 
			
		||||
	geometry.xOrigin = geometry.yOrigin = 0;
 | 
			
		||||
	geometry.rect = IntRect();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Scene::insert(SceneElement &element)
 | 
			
		||||
{
 | 
			
		||||
	IntruListLink<SceneElement> *iter;
 | 
			
		||||
 | 
			
		||||
	for (iter = elements.begin(); iter != elements.end(); iter = iter->next)
 | 
			
		||||
	{
 | 
			
		||||
		SceneElement *e = iter->data;
 | 
			
		||||
 | 
			
		||||
		if (element.z <= e->z)
 | 
			
		||||
		{
 | 
			
		||||
			if (element.z == e->z)
 | 
			
		||||
				if (element.creationStamp > e->creationStamp)
 | 
			
		||||
					continue;
 | 
			
		||||
 | 
			
		||||
			elements.insertBefore(element.link, *iter);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	elements.append(element.link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Scene::reinsert(SceneElement &element)
 | 
			
		||||
{
 | 
			
		||||
	elements.remove(element.link);
 | 
			
		||||
	insert(element);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Scene::notifyGeometryChange()
 | 
			
		||||
{
 | 
			
		||||
	IntruListLink<SceneElement> *iter;
 | 
			
		||||
 | 
			
		||||
	for (iter = elements.begin(); iter != elements.end(); iter = iter->next)
 | 
			
		||||
	{
 | 
			
		||||
		iter->data->onGeometryChange(geometry);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Scene::composite()
 | 
			
		||||
{
 | 
			
		||||
	IntruListLink<SceneElement> *iter;
 | 
			
		||||
 | 
			
		||||
	for (iter = elements.begin(); iter != elements.end(); iter = iter->next)
 | 
			
		||||
	{
 | 
			
		||||
		SceneElement *e = iter->data;
 | 
			
		||||
 | 
			
		||||
		if (e->visible)
 | 
			
		||||
			e->draw();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SceneElement::SceneElement(Scene &scene, int z)
 | 
			
		||||
    : link(this),
 | 
			
		||||
      creationStamp(gState->genTimeStamp()),
 | 
			
		||||
      z(z),
 | 
			
		||||
      visible(true),
 | 
			
		||||
      scene(&scene)
 | 
			
		||||
{
 | 
			
		||||
	scene.insert(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SceneElement::~SceneElement()
 | 
			
		||||
{
 | 
			
		||||
	unlink();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SceneElement::setScene(Scene &scene)
 | 
			
		||||
{
 | 
			
		||||
	unlink();
 | 
			
		||||
 | 
			
		||||
	this->scene = &scene;
 | 
			
		||||
 | 
			
		||||
	scene.insert(*this);
 | 
			
		||||
 | 
			
		||||
	onGeometryChange(scene.getGeometry());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int SceneElement::getZ() const
 | 
			
		||||
{
 | 
			
		||||
	aboutToAccess();
 | 
			
		||||
 | 
			
		||||
	return z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SceneElement::setZ(int value)
 | 
			
		||||
{
 | 
			
		||||
	aboutToAccess();
 | 
			
		||||
 | 
			
		||||
	if (z == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	z = value;
 | 
			
		||||
	scene->reinsert(*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool SceneElement::getVisible() const
 | 
			
		||||
{
 | 
			
		||||
	aboutToAccess();
 | 
			
		||||
 | 
			
		||||
	return visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SceneElement::setVisible(bool value)
 | 
			
		||||
{
 | 
			
		||||
	aboutToAccess();
 | 
			
		||||
 | 
			
		||||
	visible = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SceneElement::unlink()
 | 
			
		||||
{
 | 
			
		||||
	scene->elements.remove(link);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										96
									
								
								src/scene.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/scene.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,96 @@
 | 
			
		|||
/*
 | 
			
		||||
** scene.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef SCENE_H
 | 
			
		||||
#define SCENE_H
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "intrulist.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
 | 
			
		||||
class SceneElement;
 | 
			
		||||
class Viewport;
 | 
			
		||||
class Window;
 | 
			
		||||
 | 
			
		||||
class Scene
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	struct Geometry
 | 
			
		||||
	{
 | 
			
		||||
		int xOrigin, yOrigin;
 | 
			
		||||
		IntRect rect;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Scene();
 | 
			
		||||
	virtual ~Scene() {}
 | 
			
		||||
 | 
			
		||||
	virtual void composite();
 | 
			
		||||
	virtual void requestViewportRender(Vec4& /*color*/, Vec4& /*flash*/, Vec4& /*tone*/) {}
 | 
			
		||||
 | 
			
		||||
	const Geometry &getGeometry() const { return geometry; }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	void insert(SceneElement &element);
 | 
			
		||||
	void reinsert(SceneElement &element);
 | 
			
		||||
 | 
			
		||||
	/* Notify all elements that geometry has changed */
 | 
			
		||||
	void notifyGeometryChange();
 | 
			
		||||
 | 
			
		||||
	IntruList<SceneElement> elements;
 | 
			
		||||
	Geometry geometry;
 | 
			
		||||
 | 
			
		||||
	friend class SceneElement;
 | 
			
		||||
	friend class Window;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SceneElement
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	SceneElement(Scene &scene, int z = 0);
 | 
			
		||||
	virtual ~SceneElement();
 | 
			
		||||
 | 
			
		||||
	void setScene(Scene &scene);
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR_VIRT( Z,       int  )
 | 
			
		||||
	DECL_ATTR_VIRT( Visible, bool )
 | 
			
		||||
 | 
			
		||||
	/* Disposable classes reimplement this to
 | 
			
		||||
	 * check if they're disposed before access */
 | 
			
		||||
	virtual void aboutToAccess() const {}
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	virtual void draw() = 0;
 | 
			
		||||
	virtual void onGeometryChange(const Scene::Geometry &) {}
 | 
			
		||||
 | 
			
		||||
	void unlink();
 | 
			
		||||
 | 
			
		||||
	IntruListLink<SceneElement> link;
 | 
			
		||||
	const unsigned int creationStamp;
 | 
			
		||||
	int z;
 | 
			
		||||
	bool visible;
 | 
			
		||||
	Scene *scene;
 | 
			
		||||
 | 
			
		||||
	friend class Scene;
 | 
			
		||||
	friend class Viewport;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SCENE_H
 | 
			
		||||
							
								
								
									
										105
									
								
								src/serial-util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								src/serial-util.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,105 @@
 | 
			
		|||
/*
 | 
			
		||||
** serial-util.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef SERIALUTIL_H
 | 
			
		||||
#define SERIALUTIL_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
typedef unsigned uint;
 | 
			
		||||
 | 
			
		||||
static inline int16_t
 | 
			
		||||
read_int16(const char *data, uint &i)
 | 
			
		||||
{
 | 
			
		||||
	int16_t result = (data[i] & 0x000000FF) | ((data[i+1] << 8) & 0x0000FF00);
 | 
			
		||||
	i += 2;
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int32_t
 | 
			
		||||
read_int32(const char *data, uint &i)
 | 
			
		||||
{
 | 
			
		||||
	int32_t result = ((data[i+0] << 0x00) & 0x000000FF)
 | 
			
		||||
	               | ((data[i+1] << 0x08) & 0x0000FF00)
 | 
			
		||||
	               | ((data[i+2] << 0x10) & 0x00FF0000)
 | 
			
		||||
	               | ((data[i+3] << 0x18) & 0xFF000000);
 | 
			
		||||
	i += 4;
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
write_int16(char **data, int16_t value)
 | 
			
		||||
{
 | 
			
		||||
	*(*data)++ = (value >> 0) & 0xFF;
 | 
			
		||||
	*(*data)++ = (value >> 8) & 0xFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
write_int32(char **data, int32_t value)
 | 
			
		||||
{
 | 
			
		||||
	*(*data)++ = (value >> 0x00) & 0xFF;
 | 
			
		||||
	*(*data)++ = (value >> 0x08) & 0xFF;
 | 
			
		||||
	*(*data)++ = (value >> 0x10) & 0xFF;
 | 
			
		||||
	*(*data)++ = (value >> 0x18) & 0xFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
union doubleInt
 | 
			
		||||
{
 | 
			
		||||
	double d;
 | 
			
		||||
	int64_t i;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
write_double(char **data, double value)
 | 
			
		||||
{
 | 
			
		||||
	doubleInt di;
 | 
			
		||||
	di.d = value;
 | 
			
		||||
 | 
			
		||||
	*(*data)++ = (di.i >> 0x00) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x08) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x10) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x18) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x20) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x28) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x30) & 0xFF;
 | 
			
		||||
	*(*data)++ = (di.i >> 0x38) & 0xFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline double
 | 
			
		||||
read_double(const char *data, uint &i)
 | 
			
		||||
{
 | 
			
		||||
	doubleInt di;
 | 
			
		||||
	di.i = (((int64_t)data[i+0] << 0x00) & 0x00000000000000FF)
 | 
			
		||||
	     | (((int64_t)data[i+1] << 0x08) & 0x000000000000FF00)
 | 
			
		||||
	     | (((int64_t)data[i+2] << 0x10) & 0x0000000000FF0000)
 | 
			
		||||
	     | (((int64_t)data[i+3] << 0x18) & 0x00000000FF000000)
 | 
			
		||||
	     | (((int64_t)data[i+4] << 0x20) & 0x000000FF00000000)
 | 
			
		||||
	     | (((int64_t)data[i+5] << 0x28) & 0x0000FF0000000000)
 | 
			
		||||
	     | (((int64_t)data[i+6] << 0x30) & 0x00FF000000000000)
 | 
			
		||||
	     | (((int64_t)data[i+7] << 0x38) & 0xFF00000000000000);
 | 
			
		||||
	i += 8;
 | 
			
		||||
 | 
			
		||||
	return di.d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // SERIALUTIL_H
 | 
			
		||||
							
								
								
									
										39
									
								
								src/serializable.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/serializable.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
/*
 | 
			
		||||
** serializable.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef SERIALIZABLE_H
 | 
			
		||||
#define SERIALIZABLE_H
 | 
			
		||||
 | 
			
		||||
struct Serializable
 | 
			
		||||
{
 | 
			
		||||
	virtual ~Serializable() {}
 | 
			
		||||
 | 
			
		||||
	virtual int serialSize() const = 0;
 | 
			
		||||
	virtual void serialize(char *buffer) const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<class C>
 | 
			
		||||
C *deserialize(const char *data)
 | 
			
		||||
{
 | 
			
		||||
	return C::deserialize(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // SERIALIZABLE_H
 | 
			
		||||
							
								
								
									
										270
									
								
								src/shader.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								src/shader.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,270 @@
 | 
			
		|||
/*
 | 
			
		||||
** shader.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "shader.h"
 | 
			
		||||
 | 
			
		||||
#include "GL/glew.h"
 | 
			
		||||
 | 
			
		||||
#include <QFile>
 | 
			
		||||
 | 
			
		||||
#include "../shader/sprite.frag.xxd"
 | 
			
		||||
#include "../shader/hue.frag.xxd"
 | 
			
		||||
#include "../shader/trans.frag.xxd"
 | 
			
		||||
#include "../shader/transSimple.frag.xxd"
 | 
			
		||||
#include "../shader/bitmapBlit.frag.xxd"
 | 
			
		||||
 | 
			
		||||
#define GET_U(name) u_##name = glGetUniformLocation(program, #name)
 | 
			
		||||
 | 
			
		||||
FragShader::~FragShader()
 | 
			
		||||
{
 | 
			
		||||
	glUseProgram(0);
 | 
			
		||||
	glDeleteProgram(program);
 | 
			
		||||
	glDeleteShader(shader);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FragShader::bind()
 | 
			
		||||
{
 | 
			
		||||
	glUseProgram(program);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FragShader::unbind()
 | 
			
		||||
{
 | 
			
		||||
	glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
	glUseProgram(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FragShader::init(const unsigned char *source, int length)
 | 
			
		||||
{
 | 
			
		||||
	GLint success;
 | 
			
		||||
 | 
			
		||||
	shader = glCreateShader(GL_FRAGMENT_SHADER);
 | 
			
		||||
	glShaderSource(shader, 1, (const GLchar**) &source, (const GLint*) &length);
 | 
			
		||||
	glCompileShader(shader);
 | 
			
		||||
 | 
			
		||||
	glGetObjectParameterivARB(shader, GL_COMPILE_STATUS, &success);
 | 
			
		||||
	Q_ASSERT(success);
 | 
			
		||||
 | 
			
		||||
	program = glCreateProgram();
 | 
			
		||||
	glAttachShader(program, shader);
 | 
			
		||||
	glLinkProgram(program);
 | 
			
		||||
 | 
			
		||||
	glGetObjectParameterivARB(program, GL_LINK_STATUS, &success);
 | 
			
		||||
	Q_ASSERT(success);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FragShader::initFromFile(const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	QFile shaderFile(filename);
 | 
			
		||||
	shaderFile.open(QFile::ReadOnly);
 | 
			
		||||
	QByteArray contents = shaderFile.readAll();
 | 
			
		||||
	shaderFile.close();
 | 
			
		||||
 | 
			
		||||
	init((const unsigned char*) contents.constData(), contents.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FragShader::setVec4Uniform(GLint location, const Vec4 &vec)
 | 
			
		||||
{
 | 
			
		||||
	glUniform4f(location, vec.x, vec.y, vec.z, vec.w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FragShader::setTexUniform(GLint location, unsigned unitIndex, Tex::ID texture)
 | 
			
		||||
{
 | 
			
		||||
	GLenum texUnit = GL_TEXTURE0 + unitIndex;
 | 
			
		||||
 | 
			
		||||
	glActiveTexture(texUnit);
 | 
			
		||||
	glBindTexture(GL_TEXTURE_2D, texture.gl);
 | 
			
		||||
	glUniform1i(location, unitIndex);
 | 
			
		||||
	glActiveTexture(GL_TEXTURE0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TransShader::TransShader()
 | 
			
		||||
{
 | 
			
		||||
	init(shader_trans_frag,
 | 
			
		||||
	     shader_trans_frag_len);
 | 
			
		||||
 | 
			
		||||
	GET_U(currentScene);
 | 
			
		||||
	GET_U(frozenScene);
 | 
			
		||||
	GET_U(transMap);
 | 
			
		||||
	GET_U(prog);
 | 
			
		||||
	GET_U(vague);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TransShader::setCurrentScene(Tex::ID tex)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_currentScene, 0, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TransShader::setFrozenScene(Tex::ID tex)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_frozenScene, 1, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TransShader::setTransMap(Tex::ID tex)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_transMap, 2, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TransShader::setProg(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_prog, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TransShader::setVague(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_vague, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SimpleTransShader::SimpleTransShader()
 | 
			
		||||
{
 | 
			
		||||
	init(shader_transSimple_frag,
 | 
			
		||||
	     shader_transSimple_frag_len);
 | 
			
		||||
 | 
			
		||||
	GET_U(currentScene);
 | 
			
		||||
	GET_U(frozenScene);
 | 
			
		||||
	GET_U(prog);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimpleTransShader::setCurrentScene(Tex::ID tex)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_currentScene, 0, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimpleTransShader::setFrozenScene(Tex::ID tex)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_frozenScene, 1, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SimpleTransShader::setProg(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_prog, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SpriteShader::SpriteShader()
 | 
			
		||||
{
 | 
			
		||||
	init(shader_sprite_frag,
 | 
			
		||||
	     shader_sprite_frag_len);
 | 
			
		||||
 | 
			
		||||
	GET_U(tone);
 | 
			
		||||
	GET_U(color);
 | 
			
		||||
	GET_U(flash);
 | 
			
		||||
	GET_U(opacity);
 | 
			
		||||
	GET_U(bushDepth);
 | 
			
		||||
	GET_U(bushOpacity);
 | 
			
		||||
 | 
			
		||||
	bind();
 | 
			
		||||
	resetUniforms();
 | 
			
		||||
	unbind();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::resetUniforms()
 | 
			
		||||
{
 | 
			
		||||
	setTone(Vec4());
 | 
			
		||||
	setColor(Vec4());
 | 
			
		||||
	setFlash(Vec4());
 | 
			
		||||
	setOpacity(1);
 | 
			
		||||
	setBushDepth(0);
 | 
			
		||||
	setBushOpacity(0.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::setTone(const Vec4 &tone)
 | 
			
		||||
{
 | 
			
		||||
	setVec4Uniform(u_tone, tone);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::setColor(const Vec4 &color)
 | 
			
		||||
{
 | 
			
		||||
	setVec4Uniform(u_color, color);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::setFlash(const Vec4 &flash)
 | 
			
		||||
{
 | 
			
		||||
	setVec4Uniform(u_flash, flash);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::setOpacity(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_opacity, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::setBushDepth(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_bushDepth, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SpriteShader::setBushOpacity(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_bushOpacity, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HueShader::HueShader()
 | 
			
		||||
{
 | 
			
		||||
	init(shader_hue_frag,
 | 
			
		||||
	     shader_hue_frag_len);
 | 
			
		||||
 | 
			
		||||
	GET_U(hueAdjust);
 | 
			
		||||
	GET_U(inputTexture);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HueShader::setHueAdjust(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_hueAdjust, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HueShader::setInputTexture(Tex::ID tex)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_inputTexture, 0, tex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
BltShader::BltShader()
 | 
			
		||||
{
 | 
			
		||||
	init(shader_bitmapBlit_frag,
 | 
			
		||||
	     shader_bitmapBlit_frag_len);
 | 
			
		||||
 | 
			
		||||
	GET_U(source);
 | 
			
		||||
	GET_U(destination);
 | 
			
		||||
	GET_U(subRect);
 | 
			
		||||
	GET_U(opacity);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BltShader::setSource()
 | 
			
		||||
{
 | 
			
		||||
	glUniform1i(u_source, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BltShader::setDestination(const Tex::ID value)
 | 
			
		||||
{
 | 
			
		||||
	setTexUniform(u_destination, 1, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BltShader::setSubRect(const FloatRect &value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform4f(u_subRect, value.x, value.y, value.w, value.h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BltShader::setOpacity(float value)
 | 
			
		||||
{
 | 
			
		||||
	glUniform1f(u_opacity, value);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										120
									
								
								src/shader.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/shader.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,120 @@
 | 
			
		|||
/*
 | 
			
		||||
** shader.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef SHADER_H
 | 
			
		||||
#define SHADER_H
 | 
			
		||||
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
 | 
			
		||||
class FragShader
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	void bind();
 | 
			
		||||
	static void unbind();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	~FragShader();
 | 
			
		||||
 | 
			
		||||
	void init(const unsigned char *source, int length);
 | 
			
		||||
	void initFromFile(const char *filename);
 | 
			
		||||
 | 
			
		||||
	void setVec4Uniform(GLint location, const Vec4 &vec);
 | 
			
		||||
	void setTexUniform(GLint location, unsigned unitIndex, Tex::ID texture);
 | 
			
		||||
 | 
			
		||||
	GLuint shader;
 | 
			
		||||
	GLuint program;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class TransShader : public FragShader
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	TransShader();
 | 
			
		||||
 | 
			
		||||
	void setCurrentScene(Tex::ID tex);
 | 
			
		||||
	void setFrozenScene(Tex::ID tex);
 | 
			
		||||
	void setTransMap(Tex::ID tex);
 | 
			
		||||
	void setProg(float value);
 | 
			
		||||
	void setVague(float value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GLint u_currentScene, u_frozenScene, u_transMap, u_prog, u_vague;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SimpleTransShader : public FragShader
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	SimpleTransShader();
 | 
			
		||||
 | 
			
		||||
	void setCurrentScene(Tex::ID tex);
 | 
			
		||||
	void setFrozenScene(Tex::ID tex);
 | 
			
		||||
	void setProg(float value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GLint u_currentScene, u_frozenScene, u_prog;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SpriteShader : public FragShader
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	SpriteShader();
 | 
			
		||||
 | 
			
		||||
	void resetUniforms();
 | 
			
		||||
	void setTone(const Vec4 &value);
 | 
			
		||||
	void setColor(const Vec4 &value);
 | 
			
		||||
	void setFlash(const Vec4 &value);
 | 
			
		||||
	void setOpacity(float value);
 | 
			
		||||
	void setBushDepth(float value);
 | 
			
		||||
	void setBushOpacity(float value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GLint u_tone, u_opacity, u_color, u_flash, u_bushDepth, u_bushOpacity;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class HueShader : public FragShader
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	HueShader();
 | 
			
		||||
 | 
			
		||||
	void setHueAdjust(float value);
 | 
			
		||||
	void setInputTexture(Tex::ID tex);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GLint u_hueAdjust, u_inputTexture;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Bitmap blit */
 | 
			
		||||
class BltShader : public FragShader
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	BltShader();
 | 
			
		||||
 | 
			
		||||
	void setSource();
 | 
			
		||||
	void setDestination(const Tex::ID value);
 | 
			
		||||
	void setDestCoorF(const Vec2 &value);
 | 
			
		||||
	void setSubRect(const FloatRect &value);
 | 
			
		||||
	void setOpacity(float value);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	GLint u_source, u_destination, u_subRect, u_opacity;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SHADER_H
 | 
			
		||||
							
								
								
									
										351
									
								
								src/sprite.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										351
									
								
								src/sprite.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,351 @@
 | 
			
		|||
/*
 | 
			
		||||
** sprite.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "sprite.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "bitmap.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
#include "transform.h"
 | 
			
		||||
#include "shader.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
 | 
			
		||||
#include "sigc++/connection.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
struct SpritePrivate
 | 
			
		||||
{
 | 
			
		||||
	Bitmap *bitmap;
 | 
			
		||||
 | 
			
		||||
	Quad quad;
 | 
			
		||||
	Transform trans;
 | 
			
		||||
 | 
			
		||||
	Rect *srcRect;
 | 
			
		||||
	sigc::connection srcRectCon;
 | 
			
		||||
 | 
			
		||||
	bool mirrored;
 | 
			
		||||
	int bushDepth;
 | 
			
		||||
	float efBushDepth;
 | 
			
		||||
	NormValue bushOpacity;
 | 
			
		||||
	NormValue opacity;
 | 
			
		||||
	BlendType blendType;
 | 
			
		||||
 | 
			
		||||
	Color *color;
 | 
			
		||||
	Tone *tone;
 | 
			
		||||
 | 
			
		||||
	EtcTemps tmp;
 | 
			
		||||
 | 
			
		||||
	SpritePrivate()
 | 
			
		||||
	    : bitmap(0),
 | 
			
		||||
	      srcRect(&tmp.rect),
 | 
			
		||||
	      mirrored(false),
 | 
			
		||||
	      bushDepth(0),
 | 
			
		||||
	      efBushDepth(0),
 | 
			
		||||
	      bushOpacity(128),
 | 
			
		||||
	      opacity(255),
 | 
			
		||||
	      blendType(BlendNormal),
 | 
			
		||||
	      color(&tmp.color),
 | 
			
		||||
	      tone(&tmp.tone)
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		updateSrcRectCon();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~SpritePrivate()
 | 
			
		||||
	{
 | 
			
		||||
		srcRectCon.disconnect();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void recomputeBushDepth()
 | 
			
		||||
	{
 | 
			
		||||
		/* Calculate effective (normalized) bush depth */
 | 
			
		||||
		float texBushDepth = (bushDepth / trans.getScale().y) -
 | 
			
		||||
		                     (srcRect->y + srcRect->height) +
 | 
			
		||||
		                     bitmap->height();
 | 
			
		||||
 | 
			
		||||
		efBushDepth = 1.0 - texBushDepth / bitmap->height();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void onSrcRectChange()
 | 
			
		||||
	{
 | 
			
		||||
		if (mirrored)
 | 
			
		||||
			quad.setTexRect(srcRect->toFloatRect().hFlipped());
 | 
			
		||||
		else
 | 
			
		||||
			quad.setTexRect(srcRect->toFloatRect());
 | 
			
		||||
 | 
			
		||||
		quad.setPosRect(IntRect(0, 0, srcRect->width, srcRect->height));
 | 
			
		||||
		recomputeBushDepth();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateSrcRectCon()
 | 
			
		||||
	{
 | 
			
		||||
		/* Cut old connection */
 | 
			
		||||
		srcRectCon.disconnect();
 | 
			
		||||
		/* Create new one */
 | 
			
		||||
		srcRectCon = srcRect->valueChanged.connect
 | 
			
		||||
				(sigc::mem_fun(this, &SpritePrivate::onSrcRectChange));
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Sprite::Sprite(Viewport *viewport)
 | 
			
		||||
	: ViewportElement(viewport)
 | 
			
		||||
{
 | 
			
		||||
	p = new SpritePrivate;
 | 
			
		||||
	onGeometryChange(scene->getGeometry());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Sprite::~Sprite()
 | 
			
		||||
{
 | 
			
		||||
	dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DISP_CLASS_NAME "sprite"
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, Bitmap,    Bitmap*, p->bitmap)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, SrcRect,   Rect*,   p->srcRect)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, X,         int,     p->trans.getPosition().x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, Y,         int,     p->trans.getPosition().y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, OX,        int,     p->trans.getOrigin().x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, OY,        int,     p->trans.getOrigin().y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, ZoomX,     float,   p->trans.getScale().x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, ZoomY,     float,   p->trans.getScale().y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, Angle,     float,   p->trans.getRotation())
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, Mirror,    bool,    p->mirrored)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, BushDepth, int,     p->bushDepth)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, BlendType, int,     p->blendType)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, Width,     int,     p->srcRect->width)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Sprite, Height,    int,     p->srcRect->height)
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE(Sprite, BushOpacity, int,    p->bushOpacity)
 | 
			
		||||
DEF_ATTR_SIMPLE(Sprite, Opacity,     int,    p->opacity)
 | 
			
		||||
DEF_ATTR_SIMPLE(Sprite, Color,       Color*, p->color)
 | 
			
		||||
DEF_ATTR_SIMPLE(Sprite, Tone,        Tone*,  p->tone)
 | 
			
		||||
 | 
			
		||||
void Sprite::setBitmap(Bitmap *bitmap)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->bitmap == bitmap)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->bitmap = bitmap;
 | 
			
		||||
	*p->srcRect = bitmap->rect();
 | 
			
		||||
	p->onSrcRectChange();
 | 
			
		||||
	p->quad.setPosRect(p->srcRect->toFloatRect());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setSrcRect(Rect *rect)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->srcRect == rect)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->srcRect = rect;
 | 
			
		||||
	p->updateSrcRectCon();
 | 
			
		||||
 | 
			
		||||
	if (p->bitmap)
 | 
			
		||||
		p->onSrcRectChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setX(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getPosition().x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setPosition(Vec2(value, getY()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setY(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getPosition().y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setPosition(Vec2(getX(), value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setOX(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getOrigin().x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setOrigin(Vec2(value, getOY()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setOY(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getOrigin().y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setOrigin(Vec2(getOX(), value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setZoomX(float value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getScale().x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setScale(Vec2(value, getZoomY()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setZoomY(float value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getScale().y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setScale(Vec2(getZoomX(), value));
 | 
			
		||||
	p->recomputeBushDepth();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setAngle(float value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->trans.getRotation() == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->trans.setRotation(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setMirror(bool mirrored)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->mirrored == mirrored)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->mirrored = mirrored;
 | 
			
		||||
	p->onSrcRectChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setBushDepth(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->bushDepth == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->bushDepth = value;
 | 
			
		||||
	p->recomputeBushDepth();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::setBlendType(int type)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	switch (type)
 | 
			
		||||
	{
 | 
			
		||||
	default :
 | 
			
		||||
	case BlendNormal :
 | 
			
		||||
		p->blendType = BlendNormal;
 | 
			
		||||
		return;
 | 
			
		||||
	case BlendAddition :
 | 
			
		||||
		p->blendType = BlendAddition;
 | 
			
		||||
		return;
 | 
			
		||||
	case BlendSubstraction :
 | 
			
		||||
		p->blendType = BlendSubstraction;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Disposable */
 | 
			
		||||
void Sprite::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
	unlink();
 | 
			
		||||
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* SceneElement */
 | 
			
		||||
void Sprite::draw()
 | 
			
		||||
{
 | 
			
		||||
	if (!p->bitmap)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (p->bitmap->isDisposed())
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (emptyFlashFlag)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (p->color->hasEffect() || p->tone->hasEffect() || p->opacity != 255 || flashing || p->bushDepth != 0)
 | 
			
		||||
	{
 | 
			
		||||
		SpriteShader &shader = gState->spriteShader();
 | 
			
		||||
 | 
			
		||||
		shader.bind();
 | 
			
		||||
		shader.setFlash(Vec4());
 | 
			
		||||
		shader.setTone(p->tone->norm);
 | 
			
		||||
		shader.setOpacity(p->opacity.norm);
 | 
			
		||||
		shader.setBushDepth(p->efBushDepth);
 | 
			
		||||
		shader.setBushOpacity(p->bushOpacity.norm);
 | 
			
		||||
 | 
			
		||||
		/* When both flashing and effective color are set,
 | 
			
		||||
		 * the one with higher alpha will be blended */
 | 
			
		||||
		const Vec4 *blend = (flashing && flashColor.w > p->color->norm.w) ?
 | 
			
		||||
			                 &flashColor : &p->color->norm;
 | 
			
		||||
 | 
			
		||||
		shader.setColor(*blend);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	glState.blendMode.pushSet(p->blendType);
 | 
			
		||||
 | 
			
		||||
	glPushMatrix();
 | 
			
		||||
	glLoadMatrixf(p->trans.getMatrix());
 | 
			
		||||
 | 
			
		||||
	p->bitmap->flush();
 | 
			
		||||
	p->bitmap->bindTexWithMatrix();
 | 
			
		||||
 | 
			
		||||
	p->quad.draw();
 | 
			
		||||
 | 
			
		||||
	glPopMatrix();
 | 
			
		||||
 | 
			
		||||
	glState.blendMode.pop();
 | 
			
		||||
 | 
			
		||||
	FragShader::unbind();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Sprite::onGeometryChange(const Scene::Geometry &geo)
 | 
			
		||||
{
 | 
			
		||||
	/* Offset at which the sprite will be drawn
 | 
			
		||||
	 * relative to screen origin */
 | 
			
		||||
	int xOffset = geo.rect.x - geo.xOrigin;
 | 
			
		||||
	int yOffset = geo.rect.y - geo.yOrigin;
 | 
			
		||||
 | 
			
		||||
	p->trans.setGlobalOffset(xOffset, yOffset);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								src/sprite.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/sprite.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,73 @@
 | 
			
		|||
/*
 | 
			
		||||
** sprite.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef SPRITE_H
 | 
			
		||||
#define SPRITE_H
 | 
			
		||||
 | 
			
		||||
#include "scene.h"
 | 
			
		||||
#include "flashable.h"
 | 
			
		||||
#include "disposable.h"
 | 
			
		||||
#include "viewport.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
class Bitmap;
 | 
			
		||||
struct Color;
 | 
			
		||||
struct Tone;
 | 
			
		||||
struct Rect;
 | 
			
		||||
 | 
			
		||||
struct SpritePrivate;
 | 
			
		||||
 | 
			
		||||
class Sprite : public ViewportElement, public Flashable, public Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Sprite(Viewport *viewport = 0);
 | 
			
		||||
	~Sprite();
 | 
			
		||||
 | 
			
		||||
	int getWidth()  const;
 | 
			
		||||
	int getHeight() const;
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Bitmap,      Bitmap* )
 | 
			
		||||
	DECL_ATTR( SrcRect,     Rect*   )
 | 
			
		||||
	DECL_ATTR( X,           int     )
 | 
			
		||||
	DECL_ATTR( Y,           int     )
 | 
			
		||||
	DECL_ATTR( OX,          int     )
 | 
			
		||||
	DECL_ATTR( OY,          int     )
 | 
			
		||||
	DECL_ATTR( ZoomX,       float   )
 | 
			
		||||
	DECL_ATTR( ZoomY,       float   )
 | 
			
		||||
	DECL_ATTR( Angle,       float   )
 | 
			
		||||
	DECL_ATTR( Mirror,      bool    )
 | 
			
		||||
	DECL_ATTR( BushDepth,   int     )
 | 
			
		||||
	DECL_ATTR( BushOpacity, int     )
 | 
			
		||||
	DECL_ATTR( Opacity,     int     )
 | 
			
		||||
	DECL_ATTR( BlendType,   int     )
 | 
			
		||||
	DECL_ATTR( Color,       Color*  )
 | 
			
		||||
	DECL_ATTR( Tone,        Tone*   )
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	SpritePrivate *p;
 | 
			
		||||
 | 
			
		||||
	void draw();
 | 
			
		||||
	void onGeometryChange(const Scene::Geometry &);
 | 
			
		||||
 | 
			
		||||
	void releaseResources();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // SPRITE_H
 | 
			
		||||
							
								
								
									
										211
									
								
								src/table.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								src/table.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,211 @@
 | 
			
		|||
/*
 | 
			
		||||
** table.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "table.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include "serial-util.h"
 | 
			
		||||
#include "exception.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
 | 
			
		||||
 | 
			
		||||
/* Init normally */
 | 
			
		||||
Table::Table(int x, int y /*= 1*/, int z /*= 1*/)
 | 
			
		||||
	:m_x(x), m_y(y), m_z(z)
 | 
			
		||||
{
 | 
			
		||||
	data = static_cast<int16_t*>(calloc(x * y * z, sizeof(int16_t)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Table::~Table()
 | 
			
		||||
{
 | 
			
		||||
	free(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int16_t Table::get(int x, int y, int z) const
 | 
			
		||||
{
 | 
			
		||||
	return data[m_x*m_y*z + m_x*y + x];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Table::set(int16_t value, int x, int y, int z)
 | 
			
		||||
{
 | 
			
		||||
	data[m_x*m_y*z + m_x*y + x] = value;
 | 
			
		||||
 | 
			
		||||
	modified();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Table::resize(int x, int y, int z)
 | 
			
		||||
{
 | 
			
		||||
	if (x == m_x && y == m_y && z == m_z)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Fastpath: only z changed
 | 
			
		||||
	if (x == m_x && y == m_y)
 | 
			
		||||
	{
 | 
			
		||||
		data = static_cast<int16_t*>(realloc(data, m_x * m_y * z * sizeof(int16_t)));
 | 
			
		||||
		int diff = z - m_z;
 | 
			
		||||
		if (diff > 0)
 | 
			
		||||
			memset(data + (m_x * m_y * m_z), 0, diff * m_x * m_y * sizeof(int16_t));
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		int16_t *newData = static_cast<int16_t*>(calloc(x * y * z, sizeof(int16_t)));
 | 
			
		||||
 | 
			
		||||
		for (int i = 0; i < MIN(x, m_x); ++i)
 | 
			
		||||
			for (int j = 0; j < MIN(y, m_y); ++j)
 | 
			
		||||
				for (int k = 0; k < MIN(z, m_z); k++)
 | 
			
		||||
				{
 | 
			
		||||
					int index = x*y*k + x*j + i;
 | 
			
		||||
					newData[index] = at(i, j, k);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
		free(data);
 | 
			
		||||
		data = newData;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	done:
 | 
			
		||||
	m_x = x;
 | 
			
		||||
	m_y = y;
 | 
			
		||||
	m_z = z;
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Table::resize(int x, int y)
 | 
			
		||||
{
 | 
			
		||||
	if (x == m_x && y == m_y)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Fastpath: treat table as two dimensional
 | 
			
		||||
	if (m_z == 1)
 | 
			
		||||
	{
 | 
			
		||||
		// Fastpath: only y changed
 | 
			
		||||
		if (x == m_x)
 | 
			
		||||
		{
 | 
			
		||||
			data = static_cast<int16_t*>(realloc(data, m_x * y * sizeof(int16_t)));
 | 
			
		||||
			int diff = y - m_y;
 | 
			
		||||
			if (diff > 0)
 | 
			
		||||
				memset(data + (m_x * m_y), 0, diff * m_x * sizeof(int16_t));
 | 
			
		||||
			goto done;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			int16_t *newData = static_cast<int16_t*>(calloc(x * y, sizeof(int16_t)));
 | 
			
		||||
 | 
			
		||||
			for (int i = 0; i < MIN(x, m_x); ++i)
 | 
			
		||||
				for (int j = 0; j < MIN(y, m_y); ++j)
 | 
			
		||||
				{
 | 
			
		||||
					int index = x*j + i;
 | 
			
		||||
					newData[index] = at(i, j);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			free(data);
 | 
			
		||||
			data = newData;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		done:
 | 
			
		||||
		m_x = x;
 | 
			
		||||
		m_y = y;
 | 
			
		||||
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		resize(x, y, m_z);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Table::resize(int x)
 | 
			
		||||
{
 | 
			
		||||
	if (x == m_x)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// Fastpath: treat table as one dimensional
 | 
			
		||||
	if (m_y == 1 && m_z == 1)
 | 
			
		||||
	{
 | 
			
		||||
		data = static_cast<int16_t*>(realloc(data, x * sizeof(int16_t)));
 | 
			
		||||
		int diff = x - m_x;
 | 
			
		||||
		if (diff > 0)
 | 
			
		||||
			memset(data + (m_x), 0, diff * sizeof(int16_t));
 | 
			
		||||
 | 
			
		||||
		m_x = x;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resize(x, m_y);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Serializable */
 | 
			
		||||
int Table::serialSize() const
 | 
			
		||||
{
 | 
			
		||||
	/* header + data */
 | 
			
		||||
	return 20 + (m_x * m_y * m_z) * 2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Table::serialize(char *buffer) const
 | 
			
		||||
{
 | 
			
		||||
	char *buff_p = buffer;
 | 
			
		||||
 | 
			
		||||
	write_int32(&buff_p, 3);
 | 
			
		||||
	write_int32(&buff_p, m_x);
 | 
			
		||||
	write_int32(&buff_p, m_y);
 | 
			
		||||
	write_int32(&buff_p, m_z);
 | 
			
		||||
	write_int32(&buff_p, m_x * m_y * m_z);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < m_z; ++i)
 | 
			
		||||
		for (int j = 0; j < m_y; ++j)
 | 
			
		||||
			for (int k = 0; k < m_x; k++)
 | 
			
		||||
				write_int16(&buff_p, at(k, j, i));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Table *Table::deserialize(const char *data, int len)
 | 
			
		||||
{
 | 
			
		||||
	if (len < 20)
 | 
			
		||||
		throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
 | 
			
		||||
 | 
			
		||||
	uint idx = 0;
 | 
			
		||||
 | 
			
		||||
	read_int32(data, idx);
 | 
			
		||||
	int x = read_int32(data, idx);
 | 
			
		||||
	int y = read_int32(data, idx);
 | 
			
		||||
	int z = read_int32(data, idx);
 | 
			
		||||
	int size = read_int32(data, idx);
 | 
			
		||||
 | 
			
		||||
	if (size != x*y*z)
 | 
			
		||||
		throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
 | 
			
		||||
 | 
			
		||||
	if (len != 20 + x*y*z*2)
 | 
			
		||||
		throw Exception(Exception::RGSSError, "Marshal: Table: bad file format");
 | 
			
		||||
 | 
			
		||||
	Table *t = new Table(x, y, z);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < z; ++i)
 | 
			
		||||
		for (int j = 0; j < y; ++j)
 | 
			
		||||
			for (int k = 0; k < x; k++)
 | 
			
		||||
				t->at(k, j, i) = read_int16(data, idx);
 | 
			
		||||
 | 
			
		||||
	return t;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										73
									
								
								src/table.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/table.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,73 @@
 | 
			
		|||
/*
 | 
			
		||||
** table.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef TABLE_H
 | 
			
		||||
#define TABLE_H
 | 
			
		||||
 | 
			
		||||
#include "serializable.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "sigc++/signal.h"
 | 
			
		||||
 | 
			
		||||
class Table : public Serializable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Table(int x, int y = 1, int z = 1);
 | 
			
		||||
	~Table();
 | 
			
		||||
 | 
			
		||||
	int xSize() const { return m_x; }
 | 
			
		||||
	int ySize() const { return m_y; }
 | 
			
		||||
	int zSize() const { return m_z; }
 | 
			
		||||
 | 
			
		||||
	int16_t get(int x, int y = 0, int z = 0) const;
 | 
			
		||||
	void set(int16_t value, int x, int y = 0, int z = 0);
 | 
			
		||||
 | 
			
		||||
	inline int16_t &at(int x, int y = 0, int z = 0)
 | 
			
		||||
	{
 | 
			
		||||
		int16_t &value = data[m_x*m_y*z + m_x*y + x];
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inline int16_t &at(int x, int y = 0, int z = 0) const
 | 
			
		||||
	{
 | 
			
		||||
		int16_t &value = data[m_x*m_y*z + m_x*y + x];
 | 
			
		||||
 | 
			
		||||
		return value;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void resize(int x, int y, int z);
 | 
			
		||||
	void resize(int x, int y);
 | 
			
		||||
	void resize(int x);
 | 
			
		||||
 | 
			
		||||
	int serialSize() const;
 | 
			
		||||
	void serialize(char *buffer) const;
 | 
			
		||||
	static Table *deserialize(const char *data, int len);
 | 
			
		||||
 | 
			
		||||
	sigc::signal<void> modified;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	int m_x, m_y, m_z;
 | 
			
		||||
 | 
			
		||||
	int16_t *data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // TABLE_H
 | 
			
		||||
							
								
								
									
										204
									
								
								src/texpool.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								src/texpool.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,204 @@
 | 
			
		|||
/*
 | 
			
		||||
** texpool.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "texpool.h"
 | 
			
		||||
 | 
			
		||||
#include <QHash>
 | 
			
		||||
#include <QQueue>
 | 
			
		||||
#include <QList>
 | 
			
		||||
#include <QLinkedList>
 | 
			
		||||
#include <QPair>
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
typedef QPair<quint16, quint16> Size;
 | 
			
		||||
typedef QQueue<TexFBO> ObjList;
 | 
			
		||||
 | 
			
		||||
static quint32 byteCount(Size &s)
 | 
			
		||||
{
 | 
			
		||||
	return s.first * s.second * 4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct CacheObject
 | 
			
		||||
{
 | 
			
		||||
	TexFBO obj;
 | 
			
		||||
	QLinkedList<TexFBO>::iterator prioIter;
 | 
			
		||||
 | 
			
		||||
	bool operator==(const CacheObject &o)
 | 
			
		||||
	{
 | 
			
		||||
		return obj == o.obj;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef QList<CacheObject> CObjList;
 | 
			
		||||
 | 
			
		||||
struct TexPoolPrivate
 | 
			
		||||
{
 | 
			
		||||
	/* Contains all cached TexFBOs, grouped by size */
 | 
			
		||||
	QHash<Size, CObjList> poolHash;
 | 
			
		||||
 | 
			
		||||
	/* Contains all cached TexFBOs, sorted by release time */
 | 
			
		||||
	QLinkedList<TexFBO> priorityQueue;
 | 
			
		||||
 | 
			
		||||
	/* Maximal allowed cache memory */
 | 
			
		||||
	const quint32 maxMemSize;
 | 
			
		||||
 | 
			
		||||
	/* Current amound of memory consumed by the cache */
 | 
			
		||||
	quint32 memSize;
 | 
			
		||||
 | 
			
		||||
	/* Current amount of TexFBOs cached */
 | 
			
		||||
	quint16 objCount;
 | 
			
		||||
 | 
			
		||||
	/* Has this pool been disabled? */
 | 
			
		||||
	bool disabled;
 | 
			
		||||
 | 
			
		||||
	TexPoolPrivate(quint32 maxMemSize)
 | 
			
		||||
	    : maxMemSize(maxMemSize),
 | 
			
		||||
	      memSize(0),
 | 
			
		||||
	      objCount(0),
 | 
			
		||||
	      disabled(false)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TexPool::TexPool(quint32 maxMemSize)
 | 
			
		||||
{
 | 
			
		||||
	p = new TexPoolPrivate(maxMemSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TexPool::~TexPool()
 | 
			
		||||
{
 | 
			
		||||
	while (!p->priorityQueue.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		TexFBO obj = p->priorityQueue.takeFirst();
 | 
			
		||||
		TexFBO::fini(obj);
 | 
			
		||||
		--p->objCount;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Q_ASSERT(p->objCount == 0);
 | 
			
		||||
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TexFBO TexPool::request(int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	CacheObject cobj;
 | 
			
		||||
	Size size(width, height);
 | 
			
		||||
 | 
			
		||||
	/* See if we can statisfy request from cache */
 | 
			
		||||
	CObjList &bucket = p->poolHash[size];
 | 
			
		||||
 | 
			
		||||
	if (!bucket.isEmpty())
 | 
			
		||||
	{
 | 
			
		||||
		/* Found one! */
 | 
			
		||||
		cobj = bucket.takeLast();
 | 
			
		||||
 | 
			
		||||
		//p->priorityQueue.removeOne(obj);
 | 
			
		||||
		p->priorityQueue.erase(cobj.prioIter);
 | 
			
		||||
 | 
			
		||||
		p->memSize -= byteCount(size);
 | 
			
		||||
		--p->objCount;
 | 
			
		||||
 | 
			
		||||
//		qDebug() << "TexPool: <?+> (" << width << height << ")";
 | 
			
		||||
 | 
			
		||||
		return cobj.obj;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// FIXME check here that requested dimensions don't exceed OpenGL limits
 | 
			
		||||
 | 
			
		||||
	/* Nope, create it instead */
 | 
			
		||||
	TexFBO::init(cobj.obj);
 | 
			
		||||
	TexFBO::allocEmpty(cobj.obj, width, height);
 | 
			
		||||
	TexFBO::linkFBO(cobj.obj);
 | 
			
		||||
 | 
			
		||||
//	qDebug() << "TexPool: <?-> (" << width << height << ")";
 | 
			
		||||
 | 
			
		||||
	return cobj.obj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TexPool::release(TexFBO &obj)
 | 
			
		||||
{
 | 
			
		||||
	if (obj.tex == Tex::ID(0) || obj.fbo == FBO::ID(0))
 | 
			
		||||
	{
 | 
			
		||||
		TexFBO::fini(obj);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (p->disabled)
 | 
			
		||||
	{
 | 
			
		||||
		/* If we're disabled, delete without caching */
 | 
			
		||||
//		qDebug() << "TexPool: <!#> (" << obj.width << obj.height << ")";
 | 
			
		||||
		TexFBO::fini(obj);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Size size(obj.width, obj.height);
 | 
			
		||||
 | 
			
		||||
	quint32 newMemSize = p->memSize + byteCount(size);
 | 
			
		||||
 | 
			
		||||
	/* If caching this object would spill over the allowed memory budget,
 | 
			
		||||
	 * delete least used objects until we're good again */
 | 
			
		||||
	while (newMemSize > p->maxMemSize)
 | 
			
		||||
	{
 | 
			
		||||
		if (p->objCount == 0)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
//		qDebug() << "TexPool: <!~> Size:" << p->memSize;
 | 
			
		||||
 | 
			
		||||
		/* Retrieve object with lowest priority for deletion */
 | 
			
		||||
		CacheObject last;
 | 
			
		||||
		last.obj = p->priorityQueue.last();
 | 
			
		||||
		Size removedSize(last.obj.width, last.obj.height);
 | 
			
		||||
 | 
			
		||||
		CObjList &bucket = p->poolHash[removedSize];
 | 
			
		||||
		Q_ASSERT(bucket.contains(last));
 | 
			
		||||
		bucket.removeOne(last);
 | 
			
		||||
		p->priorityQueue.removeLast();
 | 
			
		||||
 | 
			
		||||
		TexFBO::fini(last.obj);
 | 
			
		||||
 | 
			
		||||
		quint32 removedMem = byteCount(removedSize);
 | 
			
		||||
		newMemSize -= removedMem;
 | 
			
		||||
		p->memSize -= removedMem;
 | 
			
		||||
		--p->objCount;
 | 
			
		||||
 | 
			
		||||
//		qDebug() << "TexPool: <!-> (" << last.obj.tex << last.obj.fbo << ")";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Retain object */
 | 
			
		||||
	p->priorityQueue.prepend(obj);
 | 
			
		||||
	CacheObject cobj;
 | 
			
		||||
	cobj.obj = obj;
 | 
			
		||||
	cobj.prioIter = p->priorityQueue.begin();
 | 
			
		||||
	CObjList &bucket = p->poolHash[size];
 | 
			
		||||
	bucket.append(cobj);
 | 
			
		||||
 | 
			
		||||
	p->memSize += byteCount(size);
 | 
			
		||||
	++p->objCount;
 | 
			
		||||
 | 
			
		||||
//	qDebug() << "TexPool: <!+> (" << obj.width << obj.height << ") Current size:" << p->memSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TexPool::disable()
 | 
			
		||||
{
 | 
			
		||||
	p->disabled = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								src/texpool.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/texpool.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
/*
 | 
			
		||||
** texpool.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef TEXPOOL_H
 | 
			
		||||
#define TEXPOOL_H
 | 
			
		||||
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
 | 
			
		||||
struct TexPoolPrivate;
 | 
			
		||||
 | 
			
		||||
class TexPool
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	TexPool(quint32 maxMemSize = 20000000 /* 20 MB */);
 | 
			
		||||
	~TexPool();
 | 
			
		||||
 | 
			
		||||
	TexFBO request(int width, int height);
 | 
			
		||||
	void release(TexFBO &obj);
 | 
			
		||||
 | 
			
		||||
	void disable();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	TexPoolPrivate *p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // TEXPOOL_H
 | 
			
		||||
							
								
								
									
										1216
									
								
								src/tilemap.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1216
									
								
								src/tilemap.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										71
									
								
								src/tilemap.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/tilemap.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
/*
 | 
			
		||||
** tilemap.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef TILEMAP_H
 | 
			
		||||
#define TILEMAP_H
 | 
			
		||||
 | 
			
		||||
#include "disposable.h"
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
class Viewport;
 | 
			
		||||
class Bitmap;
 | 
			
		||||
class Table;
 | 
			
		||||
 | 
			
		||||
struct TilemapPrivate;
 | 
			
		||||
 | 
			
		||||
class Tilemap : public Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	class Autotiles
 | 
			
		||||
	{
 | 
			
		||||
	public:
 | 
			
		||||
		void set(int i, Bitmap *bitmap);
 | 
			
		||||
		Bitmap *get(int i) const;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		TilemapPrivate *p;
 | 
			
		||||
		friend class Tilemap;
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	Tilemap(Viewport *viewport = 0);
 | 
			
		||||
	~Tilemap();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
 | 
			
		||||
	Autotiles &getAutotiles() const;
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Viewport,   Viewport* )
 | 
			
		||||
	DECL_ATTR( Tileset,    Bitmap*   )
 | 
			
		||||
	DECL_ATTR( MapData,    Table*    )
 | 
			
		||||
	DECL_ATTR( FlashData,  Table*    )
 | 
			
		||||
	DECL_ATTR( Priorities, Table*    )
 | 
			
		||||
	DECL_ATTR( Visible,    bool      )
 | 
			
		||||
	DECL_ATTR( OX,         int       )
 | 
			
		||||
	DECL_ATTR( OY,         int       )
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	TilemapPrivate *p;
 | 
			
		||||
 | 
			
		||||
	void releaseResources();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // TILEMAP_H
 | 
			
		||||
							
								
								
									
										214
									
								
								src/tilequad.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								src/tilequad.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,214 @@
 | 
			
		|||
/*
 | 
			
		||||
** tilequad.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "tilequad.h"
 | 
			
		||||
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
 | 
			
		||||
namespace TileQuads
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
int oneDimCount(int tileDimension,
 | 
			
		||||
                int destDimension)
 | 
			
		||||
{
 | 
			
		||||
	if (tileDimension <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	int fullCount = destDimension / tileDimension;
 | 
			
		||||
	int partSize  = destDimension % tileDimension;
 | 
			
		||||
 | 
			
		||||
	return fullCount + (partSize ? 1 : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int twoDimCount(int tileW, int tileH,
 | 
			
		||||
                int destW, int destH)
 | 
			
		||||
{
 | 
			
		||||
	return oneDimCount(tileW, destW) *
 | 
			
		||||
	       oneDimCount(tileH, destH);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int buildH(const IntRect &sourceRect,
 | 
			
		||||
           int width, int x, int y,
 | 
			
		||||
           Vertex *verts)
 | 
			
		||||
{
 | 
			
		||||
	if (width <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	int fullCount = width / sourceRect.w;
 | 
			
		||||
	int partSize  = width % sourceRect.w;
 | 
			
		||||
 | 
			
		||||
	FloatRect _sourceRect(sourceRect);
 | 
			
		||||
	FloatRect destRect(x, y, sourceRect.w, sourceRect.h);
 | 
			
		||||
 | 
			
		||||
	/* Full size quads */
 | 
			
		||||
	for (int x = 0; x < fullCount; ++x)
 | 
			
		||||
	{
 | 
			
		||||
		Vertex *vert = &verts[x*4];
 | 
			
		||||
 | 
			
		||||
		Quad::setTexRect(vert, _sourceRect);
 | 
			
		||||
		Quad::setPosRect(vert, destRect);
 | 
			
		||||
 | 
			
		||||
		destRect.x += sourceRect.w;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (partSize)
 | 
			
		||||
	{
 | 
			
		||||
		Vertex *vert = &verts[fullCount*4];
 | 
			
		||||
 | 
			
		||||
		_sourceRect.w = partSize;
 | 
			
		||||
		destRect.w = partSize;
 | 
			
		||||
 | 
			
		||||
		Quad::setTexRect(vert, _sourceRect);
 | 
			
		||||
		Quad::setPosRect(vert, destRect);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fullCount + (partSize ? 1 : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int buildV(const IntRect &sourceRect,
 | 
			
		||||
           int height, int ox, int oy,
 | 
			
		||||
           Vertex *verts)
 | 
			
		||||
{
 | 
			
		||||
	if (height <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	int fullCount = height / sourceRect.h;
 | 
			
		||||
	int partSize  = height % sourceRect.h;
 | 
			
		||||
 | 
			
		||||
	FloatRect _sourceRect(sourceRect);
 | 
			
		||||
	FloatRect destRect(ox, oy, sourceRect.w, sourceRect.h);
 | 
			
		||||
 | 
			
		||||
	/* Full size quads */
 | 
			
		||||
	for (int y = 0; y < fullCount; ++y)
 | 
			
		||||
	{
 | 
			
		||||
		Vertex *vert = &verts[y*4];
 | 
			
		||||
 | 
			
		||||
		Quad::setTexRect(vert, _sourceRect);
 | 
			
		||||
		Quad::setPosRect(vert, destRect);
 | 
			
		||||
 | 
			
		||||
		destRect.y += sourceRect.h;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (partSize)
 | 
			
		||||
	{
 | 
			
		||||
		Vertex *vert = &verts[fullCount*4];
 | 
			
		||||
 | 
			
		||||
		_sourceRect.h = partSize;
 | 
			
		||||
		destRect.h = partSize;
 | 
			
		||||
 | 
			
		||||
		Quad::setTexRect(vert, _sourceRect);
 | 
			
		||||
		Quad::setPosRect(vert, destRect);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fullCount + (partSize ? 1 : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int build(const IntRect &sourceRect,
 | 
			
		||||
          const IntRect &destRect,
 | 
			
		||||
          Vertex *verts)
 | 
			
		||||
{
 | 
			
		||||
	int ox = destRect.x;
 | 
			
		||||
	int oy = destRect.y;
 | 
			
		||||
	int width = destRect.w;
 | 
			
		||||
	int height = destRect.h;
 | 
			
		||||
 | 
			
		||||
	if (width <= 0 || height <= 0)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	int fullCount = height / sourceRect.h;
 | 
			
		||||
	int partSize  = height % sourceRect.h;
 | 
			
		||||
 | 
			
		||||
	int rowTileCount = oneDimCount(sourceRect.w, width);
 | 
			
		||||
 | 
			
		||||
	int qCount = 0;
 | 
			
		||||
 | 
			
		||||
	int v = 0;
 | 
			
		||||
	for (int i = 0; i < fullCount; ++i)
 | 
			
		||||
	{
 | 
			
		||||
		qCount += buildH(sourceRect, width, ox, oy, &verts[v]);
 | 
			
		||||
 | 
			
		||||
		v += rowTileCount*4;
 | 
			
		||||
		oy += sourceRect.h;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (partSize)
 | 
			
		||||
	{
 | 
			
		||||
		IntRect partSourceRect = sourceRect;
 | 
			
		||||
		partSourceRect.h = partSize;
 | 
			
		||||
 | 
			
		||||
		qCount += buildH(partSourceRect, width, ox, oy, &verts[v]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return qCount;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void buildFrameInt(const IntRect &rect,
 | 
			
		||||
                          FloatRect *quadRects /* 9 big */)
 | 
			
		||||
{
 | 
			
		||||
	int w  = rect.w; int h  = rect.h;
 | 
			
		||||
	int x1 = rect.x; int x2 = x1 + w;
 | 
			
		||||
	int y1 = rect.y; int y2 = y1 + h;
 | 
			
		||||
 | 
			
		||||
	int i = 0;
 | 
			
		||||
	/* Corners - tl, tr, br, bl */
 | 
			
		||||
	quadRects[i++] = FloatRect(x1,   y1,   2, 2);
 | 
			
		||||
	quadRects[i++] = FloatRect(x2-2, y1,   2, 2);
 | 
			
		||||
	quadRects[i++] = FloatRect(x2-2, y2-2, 2, 2);
 | 
			
		||||
	quadRects[i++] = FloatRect(x1,   y2-2, 2, 2);
 | 
			
		||||
 | 
			
		||||
	/* Sides - l, r, t, b */
 | 
			
		||||
	quadRects[i++] = FloatRect(x1,   y1+2, 2,   h-4);
 | 
			
		||||
	quadRects[i++] = FloatRect(x2-2, y1+2, 2,   h-4);
 | 
			
		||||
	quadRects[i++] = FloatRect(x1+2, y1,   w-4, 2);
 | 
			
		||||
	quadRects[i++] = FloatRect(x1+2, y2-2, w-4, 2);
 | 
			
		||||
 | 
			
		||||
	/* Center */
 | 
			
		||||
	quadRects[i++] = FloatRect(x1+2, y1+2, w-4, h-4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int buildFrameSource(const IntRect &rect,
 | 
			
		||||
                     Vertex *vert /* 36 big */)
 | 
			
		||||
{
 | 
			
		||||
	FloatRect quadRects[9];
 | 
			
		||||
 | 
			
		||||
	buildFrameInt(rect, quadRects);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < 9; ++i)
 | 
			
		||||
		Quad::setTexRect(&vert[i*4], quadRects[i]);
 | 
			
		||||
 | 
			
		||||
	return 9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int buildFrame(const IntRect &rect,
 | 
			
		||||
               Vertex *vert /* 36 big */)
 | 
			
		||||
{
 | 
			
		||||
	FloatRect quadRects[9];
 | 
			
		||||
 | 
			
		||||
	buildFrameInt(rect, quadRects);
 | 
			
		||||
 | 
			
		||||
	for (int i = 0; i < 9; ++i)
 | 
			
		||||
		Quad::setPosRect(&vert[i*4], quadRects[i]);
 | 
			
		||||
 | 
			
		||||
	return 9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								src/tilequad.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/tilequad.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
/*
 | 
			
		||||
** tilequad.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef TILEQUAD_H
 | 
			
		||||
#define TILEQUAD_H
 | 
			
		||||
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
 | 
			
		||||
#include <QVector>
 | 
			
		||||
 | 
			
		||||
/* Tiled Quads
 | 
			
		||||
 *
 | 
			
		||||
 * These functions enable drawing a tiled subrectangle
 | 
			
		||||
 * of a texture,
 | 
			
		||||
 * but no advanced stuff like rotation, scaling etc.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "quadarray.h"
 | 
			
		||||
 | 
			
		||||
namespace TileQuads
 | 
			
		||||
{
 | 
			
		||||
	/* Calculate needed quad counts */
 | 
			
		||||
	int oneDimCount(int tileDimension,
 | 
			
		||||
					int destDimension);
 | 
			
		||||
	int twoDimCount(int tileW, int tileH,
 | 
			
		||||
					int destW, int destH);
 | 
			
		||||
 | 
			
		||||
	/* Build tiling quads */
 | 
			
		||||
	int buildH(const IntRect &sourceRect,
 | 
			
		||||
				int width, int x, int y,
 | 
			
		||||
				Vertex *verts);
 | 
			
		||||
 | 
			
		||||
	int buildV(const IntRect &sourceRect,
 | 
			
		||||
			   int height, int ox, int oy,
 | 
			
		||||
			   Vertex *verts);
 | 
			
		||||
 | 
			
		||||
	int build(const IntRect &sourceRect,
 | 
			
		||||
			  const IntRect &destRect,
 | 
			
		||||
			  Vertex *verts);
 | 
			
		||||
 | 
			
		||||
	/* Build a quad "frame" (see Window cursor_rect) */
 | 
			
		||||
	int buildFrame(const IntRect &rect,
 | 
			
		||||
				   Vertex *vert /* 36 big */);
 | 
			
		||||
 | 
			
		||||
	int buildFrameSource(const IntRect &rect,
 | 
			
		||||
						 Vertex *vert /* 36 big */);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // TILEQUAD_H
 | 
			
		||||
							
								
								
									
										140
									
								
								src/transform.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/transform.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
/*
 | 
			
		||||
 *  transform.h
 | 
			
		||||
 *
 | 
			
		||||
 *  This file is part of mkxp. It is based on parts of "SFML 2.0"
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
//
 | 
			
		||||
// SFML - Simple and Fast Multimedia Library
 | 
			
		||||
// Copyright (C) 2007-2012 Laurent Gomila (laurent.gom@gmail.com)
 | 
			
		||||
//
 | 
			
		||||
// This software is provided 'as-is', without any express or implied warranty.
 | 
			
		||||
// In no event will the authors be held liable for any damages arising from the use of this software.
 | 
			
		||||
//
 | 
			
		||||
// Permission is granted to anyone to use this software for any purpose,
 | 
			
		||||
// including commercial applications, and to alter it and redistribute it freely,
 | 
			
		||||
// subject to the following restrictions:
 | 
			
		||||
//
 | 
			
		||||
// 1. The origin of this software must not be misrepresented;
 | 
			
		||||
//    you must not claim that you wrote the original software.
 | 
			
		||||
//    If you use this software in a product, an acknowledgment
 | 
			
		||||
//    in the product documentation would be appreciated but is not required.
 | 
			
		||||
//
 | 
			
		||||
// 2. Altered source versions must be plainly marked as such,
 | 
			
		||||
//    and must not be misrepresented as being the original software.
 | 
			
		||||
//
 | 
			
		||||
// 3. This notice may not be removed or altered from any source distribution.
 | 
			
		||||
//
 | 
			
		||||
////////////////////////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef TRANSFORM_H
 | 
			
		||||
#define TRANSFORM_H
 | 
			
		||||
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "math.h"
 | 
			
		||||
#include "string.h"
 | 
			
		||||
 | 
			
		||||
class Transform
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Transform()
 | 
			
		||||
	    : scale(1, 1),
 | 
			
		||||
	      rotation(0),
 | 
			
		||||
	      xOffset(0), yOffset(0),
 | 
			
		||||
	      dirty(true)
 | 
			
		||||
	{
 | 
			
		||||
		memset(matrix, 0, sizeof(matrix));
 | 
			
		||||
 | 
			
		||||
		matrix[10] = 1;
 | 
			
		||||
		matrix[15] = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2 &getPosition() { return position; }
 | 
			
		||||
	Vec2 &getScale()    { return scale;    }
 | 
			
		||||
	Vec2 &getOrigin()   { return origin;   }
 | 
			
		||||
	float getRotation() { return rotation; }
 | 
			
		||||
 | 
			
		||||
	void setPosition(const Vec2 &value)
 | 
			
		||||
	{
 | 
			
		||||
		position = value;
 | 
			
		||||
		dirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setScale(const Vec2 &value)
 | 
			
		||||
	{
 | 
			
		||||
		scale = value;
 | 
			
		||||
		dirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setOrigin(const Vec2 &value)
 | 
			
		||||
	{
 | 
			
		||||
		origin = value;
 | 
			
		||||
		dirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setRotation(float value)
 | 
			
		||||
	{
 | 
			
		||||
		rotation = value;
 | 
			
		||||
		dirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void setGlobalOffset(int x, int y)
 | 
			
		||||
	{
 | 
			
		||||
		xOffset = x;
 | 
			
		||||
		yOffset = y;
 | 
			
		||||
		dirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const float *getMatrix()
 | 
			
		||||
	{
 | 
			
		||||
		if (dirty)
 | 
			
		||||
		{
 | 
			
		||||
			updateMatrix();
 | 
			
		||||
			dirty = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return matrix;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void updateMatrix()
 | 
			
		||||
	{
 | 
			
		||||
		if (rotation >= 360 || rotation < -360)
 | 
			
		||||
			rotation = (float) fmod(rotation, 360);
 | 
			
		||||
		if (rotation < 0)
 | 
			
		||||
			rotation += 360;
 | 
			
		||||
 | 
			
		||||
		float angle  = rotation * 3.141592654f / 180.f;
 | 
			
		||||
		float cosine = (float) cos(angle);
 | 
			
		||||
		float sine   = (float) sin(angle);
 | 
			
		||||
		float sxc    = scale.x * cosine;
 | 
			
		||||
		float syc    = scale.y * cosine;
 | 
			
		||||
		float sxs    = scale.x * sine;
 | 
			
		||||
		float sys    = scale.y * sine;
 | 
			
		||||
		float tx     = -origin.x * sxc - origin.y * sys + position.x + xOffset;
 | 
			
		||||
		float ty     =  origin.x * sxs - origin.y * syc + position.y + yOffset;
 | 
			
		||||
 | 
			
		||||
		matrix[0]  =  sxc;
 | 
			
		||||
		matrix[1]  = -sxs;
 | 
			
		||||
		matrix[4]  =  sys;
 | 
			
		||||
		matrix[5]  =  syc;
 | 
			
		||||
		matrix[12] =  tx;
 | 
			
		||||
		matrix[13] =  ty;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Vec2 position;
 | 
			
		||||
	Vec2 origin;
 | 
			
		||||
	Vec2 scale;
 | 
			
		||||
	float rotation;
 | 
			
		||||
 | 
			
		||||
	/* Silently added to position */
 | 
			
		||||
	int xOffset, yOffset;
 | 
			
		||||
 | 
			
		||||
	float matrix[16];
 | 
			
		||||
 | 
			
		||||
	bool dirty;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // TRANSFORM_H
 | 
			
		||||
							
								
								
									
										112
									
								
								src/util.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/util.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,112 @@
 | 
			
		|||
/*
 | 
			
		||||
** util.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef UTIL_H
 | 
			
		||||
#define UTIL_H
 | 
			
		||||
 | 
			
		||||
static inline int
 | 
			
		||||
wrapRange(int value, int min, int max)
 | 
			
		||||
{
 | 
			
		||||
	if (value >= min && value <= max)
 | 
			
		||||
		return value;
 | 
			
		||||
 | 
			
		||||
	while (value < min)
 | 
			
		||||
		value += (max - min);
 | 
			
		||||
 | 
			
		||||
	return value % (max - min);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
static inline T bound(T value, T min, T max)
 | 
			
		||||
{
 | 
			
		||||
	if (value < min)
 | 
			
		||||
		return min;
 | 
			
		||||
 | 
			
		||||
	if (value > max)
 | 
			
		||||
		return max;
 | 
			
		||||
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
static inline T min(T value1, T value2)
 | 
			
		||||
{
 | 
			
		||||
	return (value1 < value2) ? value1 : value2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
static inline T max(T value1, T value2)
 | 
			
		||||
{
 | 
			
		||||
	return (value1 > value2) ? value1 : value2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline int
 | 
			
		||||
findNextPow2(int start)
 | 
			
		||||
{
 | 
			
		||||
	int i = 1;
 | 
			
		||||
	while (i < start)
 | 
			
		||||
		i <<= 1;
 | 
			
		||||
 | 
			
		||||
	return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define ARRAY_SIZE(obj) (sizeof(obj) / sizeof((obj)[0]))
 | 
			
		||||
 | 
			
		||||
#define elementsN(obj) const int obj##N = ARRAY_SIZE(obj)
 | 
			
		||||
 | 
			
		||||
#define DECL_ATTR_DETAILED(name, type, keyword1, keyword2) \
 | 
			
		||||
	keyword1 type get##name() keyword2; \
 | 
			
		||||
	keyword1 void set##name(type value);
 | 
			
		||||
 | 
			
		||||
#define DECL_ATTR(name, type) DECL_ATTR_DETAILED(name, type, , const)
 | 
			
		||||
#define DECL_ATTR_VIRT(name, type) DECL_ATTR_DETAILED(name, type, virtual, const)
 | 
			
		||||
#define DECL_ATTR_STATIC(name, type) DECL_ATTR_DETAILED(name, type, static, )
 | 
			
		||||
#define DECL_ATTR_INLINE(name, type, loc) \
 | 
			
		||||
	type get##name() const { return loc; } \
 | 
			
		||||
	void set##name(type value) { loc = value; }
 | 
			
		||||
 | 
			
		||||
/* Undef this if not needed */
 | 
			
		||||
#define CHK_DISP GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
#define DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, keyword1) \
 | 
			
		||||
	type klass :: get##name() keyword1 \
 | 
			
		||||
	{ \
 | 
			
		||||
		CHK_DISP \
 | 
			
		||||
		return location; \
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#define DEF_ATTR_SIMPLE_DETAILED(klass, name, type, location, keyword1) \
 | 
			
		||||
	DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, keyword1) \
 | 
			
		||||
	void klass :: set##name(type value) \
 | 
			
		||||
{ \
 | 
			
		||||
	CHK_DISP \
 | 
			
		||||
	location = value; \
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DEF_ATTR_RD_SIMPLE(klass, name, type, location) \
 | 
			
		||||
	DEF_ATTR_RD_SIMPLE_DETAILED(klass, name, type, location, const)
 | 
			
		||||
#define DEF_ATTR_SIMPLE(klass, name, type, location) \
 | 
			
		||||
	DEF_ATTR_SIMPLE_DETAILED(klass, name, type, location, const)
 | 
			
		||||
 | 
			
		||||
#define DEF_ATTR_SIMPLE_STATIC(klass, name, type, location) \
 | 
			
		||||
	DEF_ATTR_SIMPLE_DETAILED(klass, name, type, location, )
 | 
			
		||||
 | 
			
		||||
#endif // UTIL_H
 | 
			
		||||
							
								
								
									
										245
									
								
								src/viewport.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								src/viewport.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,245 @@
 | 
			
		|||
/*
 | 
			
		||||
** viewport.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "viewport.h"
 | 
			
		||||
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
 | 
			
		||||
#include "SDL2/SDL_rect.h"
 | 
			
		||||
 | 
			
		||||
#include "sigc++/connection.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
struct ViewportPrivate
 | 
			
		||||
{
 | 
			
		||||
	/* Needed for geometry changes */
 | 
			
		||||
	Viewport *self;
 | 
			
		||||
 | 
			
		||||
	Rect *rect;
 | 
			
		||||
	sigc::connection rectCon;
 | 
			
		||||
 | 
			
		||||
	Color *color;
 | 
			
		||||
	Tone *tone;
 | 
			
		||||
 | 
			
		||||
	IntRect screenRect;
 | 
			
		||||
	int isOnScreen;
 | 
			
		||||
 | 
			
		||||
	EtcTemps tmp;
 | 
			
		||||
 | 
			
		||||
	ViewportPrivate(int x, int y, int width, int height, Viewport *self)
 | 
			
		||||
	    : self(self),
 | 
			
		||||
	      rect(&tmp.rect),
 | 
			
		||||
	      color(&tmp.color),
 | 
			
		||||
	      tone(&tmp.tone),
 | 
			
		||||
	      isOnScreen(false)
 | 
			
		||||
	{
 | 
			
		||||
		rect->set(x, y, width, height);
 | 
			
		||||
		updateRectCon();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~ViewportPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		rectCon.disconnect();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void onRectChange()
 | 
			
		||||
	{
 | 
			
		||||
		self->geometry.rect = rect->toIntRect();
 | 
			
		||||
		self->notifyGeometryChange();
 | 
			
		||||
		recomputeOnScreen();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateRectCon()
 | 
			
		||||
	{
 | 
			
		||||
		rectCon.disconnect();
 | 
			
		||||
		rectCon = rect->valueChanged.connect
 | 
			
		||||
		        (sigc::mem_fun(this, &ViewportPrivate::onRectChange));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void recomputeOnScreen()
 | 
			
		||||
	{
 | 
			
		||||
		SDL_Rect r1 = { screenRect.x, screenRect.y,
 | 
			
		||||
		                screenRect.w, screenRect.h };
 | 
			
		||||
 | 
			
		||||
		SDL_Rect r2 = { rect->x,     rect->y,
 | 
			
		||||
		                rect->width, rect->height };
 | 
			
		||||
 | 
			
		||||
		SDL_Rect result;
 | 
			
		||||
		isOnScreen = SDL_IntersectRect(&r1, &r2, &result);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool needsEffectRender(bool flashing)
 | 
			
		||||
	{
 | 
			
		||||
		bool rectEffective = !rect->isEmpty();
 | 
			
		||||
		bool colorToneEffective = color->hasEffect() || tone->hasEffect() || flashing;
 | 
			
		||||
 | 
			
		||||
		return (rectEffective && colorToneEffective && isOnScreen);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Viewport::Viewport(int x, int y, int width, int height)
 | 
			
		||||
    : SceneElement(*gState->screen()),
 | 
			
		||||
      sceneLink(this)
 | 
			
		||||
{
 | 
			
		||||
	initViewport(x, y, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Viewport::Viewport(Rect *rect)
 | 
			
		||||
    : SceneElement(*gState->screen()),
 | 
			
		||||
      sceneLink(this)
 | 
			
		||||
{
 | 
			
		||||
	initViewport(rect->x, rect->y, rect->width, rect->height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Viewport::initViewport(int x, int y, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
	p = new ViewportPrivate(x, y, width, height, this);
 | 
			
		||||
 | 
			
		||||
	/* Set our own geometry */
 | 
			
		||||
	geometry.rect = IntRect(x, y, width, height);
 | 
			
		||||
 | 
			
		||||
	/* Handle parent geometry */
 | 
			
		||||
	onGeometryChange(scene->getGeometry());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Viewport::~Viewport()
 | 
			
		||||
{
 | 
			
		||||
	dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DISP_CLASS_NAME "viewport"
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Viewport, OX,   int,   geometry.xOrigin)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Viewport, OY,   int,   geometry.yOrigin)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Viewport, Rect, Rect*, p->rect)
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE(Viewport, Color, Color*, p->color)
 | 
			
		||||
DEF_ATTR_SIMPLE(Viewport, Tone, Tone*, p->tone)
 | 
			
		||||
 | 
			
		||||
void Viewport::setOX(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (geometry.xOrigin == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	geometry.xOrigin = value;
 | 
			
		||||
	notifyGeometryChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Viewport::setOY(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (geometry.yOrigin == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	geometry.yOrigin = value;
 | 
			
		||||
	notifyGeometryChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Viewport::setRect(Rect *value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->rect == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->rect = value;
 | 
			
		||||
	p->updateRectCon();
 | 
			
		||||
	p->onRectChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Scene */
 | 
			
		||||
void Viewport::composite()
 | 
			
		||||
{
 | 
			
		||||
	if (emptyFlashFlag)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	bool renderEffect = p->needsEffectRender(flashing);
 | 
			
		||||
 | 
			
		||||
	if (elements.getSize() == 0 && !renderEffect)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	// What to do here:
 | 
			
		||||
	// 1. Setup scissor box
 | 
			
		||||
	// 2. Geometry offsets for elements should be taken care off by Scene
 | 
			
		||||
	// 3. Call Scene::composite, or manually iterate and draw??
 | 
			
		||||
 | 
			
		||||
	/* Setup scissor */
 | 
			
		||||
	glState.scissorTest.pushSet(true);
 | 
			
		||||
	glState.scissorBox.pushSet(p->rect->toIntRect());
 | 
			
		||||
 | 
			
		||||
	Scene::composite();
 | 
			
		||||
 | 
			
		||||
	/* If any effects are visible, request parent Scene to
 | 
			
		||||
	 * render them. */
 | 
			
		||||
	if (renderEffect)
 | 
			
		||||
		scene->requestViewportRender
 | 
			
		||||
		        (p->color->norm, flashColor, p->tone->norm);
 | 
			
		||||
 | 
			
		||||
	glState.scissorBox.pop();
 | 
			
		||||
	glState.scissorTest.pop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* SceneElement */
 | 
			
		||||
void Viewport::draw()
 | 
			
		||||
{
 | 
			
		||||
	composite();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Viewport::onGeometryChange(const Geometry &geo)
 | 
			
		||||
{
 | 
			
		||||
	p->screenRect = geo.rect;
 | 
			
		||||
	p->recomputeOnScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Disposable */
 | 
			
		||||
void Viewport::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
	unlink();
 | 
			
		||||
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ViewportElement::ViewportElement(Viewport *viewport, int z)
 | 
			
		||||
    : SceneElement(viewport ? *viewport : *gState->screen(), z),
 | 
			
		||||
      m_viewport(viewport)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
Viewport *ViewportElement::getViewport() const
 | 
			
		||||
{
 | 
			
		||||
	return m_viewport;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ViewportElement::setViewport(Viewport *viewport)
 | 
			
		||||
{
 | 
			
		||||
	m_viewport = viewport;
 | 
			
		||||
	setScene(viewport ? *viewport : *gState->screen());
 | 
			
		||||
	onViewportChange();
 | 
			
		||||
	onGeometryChange(scene->getGeometry());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										80
									
								
								src/viewport.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/viewport.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
/*
 | 
			
		||||
** viewport.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef VIEWPORT_H
 | 
			
		||||
#define VIEWPORT_H
 | 
			
		||||
 | 
			
		||||
#include "scene.h"
 | 
			
		||||
#include "flashable.h"
 | 
			
		||||
#include "disposable.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
#include "SFML/Graphics/Rect.hpp"
 | 
			
		||||
 | 
			
		||||
struct ViewportPrivate;
 | 
			
		||||
 | 
			
		||||
class Viewport : public Scene, public SceneElement, public Flashable, public Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Viewport(int x, int y, int width, int height);
 | 
			
		||||
	Viewport(Rect *rect);
 | 
			
		||||
	~Viewport();
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Rect,  Rect*  )
 | 
			
		||||
	DECL_ATTR( OX,    int    )
 | 
			
		||||
	DECL_ATTR( OY,    int    )
 | 
			
		||||
	DECL_ATTR( Color, Color* )
 | 
			
		||||
	DECL_ATTR( Tone,  Tone*  )
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	void initViewport(int x, int y, int width, int height);
 | 
			
		||||
	void geometryChanged();
 | 
			
		||||
 | 
			
		||||
	void composite();
 | 
			
		||||
	void draw();
 | 
			
		||||
	void onGeometryChange(const Geometry &);
 | 
			
		||||
	bool isEffectiveViewport(Rect *&, Color *&, Tone *&) const;
 | 
			
		||||
 | 
			
		||||
	void releaseResources();
 | 
			
		||||
 | 
			
		||||
	ViewportPrivate *p;
 | 
			
		||||
	friend struct ViewportPrivate;
 | 
			
		||||
 | 
			
		||||
	IntruListLink<Scene> sceneLink;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ViewportElement : public SceneElement
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	ViewportElement(Viewport *viewport = 0, int z = 0);
 | 
			
		||||
 | 
			
		||||
	Viewport *getViewport() const;
 | 
			
		||||
 | 
			
		||||
	void setViewport(Viewport *viewport = 0);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
	virtual void onViewportChange() {}
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	Viewport *m_viewport;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // VIEWPORT_H
 | 
			
		||||
							
								
								
									
										888
									
								
								src/window.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										888
									
								
								src/window.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,888 @@
 | 
			
		|||
/*
 | 
			
		||||
** window.cpp
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "window.h"
 | 
			
		||||
 | 
			
		||||
#include "viewport.h"
 | 
			
		||||
#include "globalstate.h"
 | 
			
		||||
#include "bitmap.h"
 | 
			
		||||
#include "etc.h"
 | 
			
		||||
#include "etc-internal.h"
 | 
			
		||||
#include "tilequad.h"
 | 
			
		||||
 | 
			
		||||
#include "gl-util.h"
 | 
			
		||||
#include "quad.h"
 | 
			
		||||
#include "quadarray.h"
 | 
			
		||||
#include "texpool.h"
 | 
			
		||||
#include "glstate.h"
 | 
			
		||||
 | 
			
		||||
#include "sigc++/connection.h"
 | 
			
		||||
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct Sides
 | 
			
		||||
{
 | 
			
		||||
	T l, r, t, b;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template<typename T>
 | 
			
		||||
struct Corners
 | 
			
		||||
{
 | 
			
		||||
	T tl, tr, bl, br;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static IntRect backgroundSrc(0, 0, 128, 128);
 | 
			
		||||
 | 
			
		||||
static IntRect cursorSrc(128, 64, 32, 32);
 | 
			
		||||
 | 
			
		||||
static IntRect pauseAniSrc[] =
 | 
			
		||||
{
 | 
			
		||||
	IntRect(160, 64, 16, 16),
 | 
			
		||||
	IntRect(176, 64, 16, 16),
 | 
			
		||||
	IntRect(160, 80, 16, 16),
 | 
			
		||||
	IntRect(176, 80, 16, 16)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static Sides<IntRect> bordersSrc =
 | 
			
		||||
{
 | 
			
		||||
	IntRect(128, 16, 16, 32),
 | 
			
		||||
	IntRect(176, 16, 16, 32),
 | 
			
		||||
	IntRect(144,  0, 32, 16),
 | 
			
		||||
	IntRect(144, 48, 32, 16)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static Corners<IntRect> cornersSrc =
 | 
			
		||||
{
 | 
			
		||||
	IntRect(128,  0, 16, 16),
 | 
			
		||||
	IntRect(176,  0, 16, 16),
 | 
			
		||||
	IntRect(128, 48, 16, 16),
 | 
			
		||||
	IntRect(176, 48, 16, 16)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static Sides<IntRect> scrollArrowSrc =
 | 
			
		||||
{
 | 
			
		||||
	IntRect(144, 24,  8, 16),
 | 
			
		||||
	IntRect(168, 24,  8, 16),
 | 
			
		||||
	IntRect(152, 16, 16,  8),
 | 
			
		||||
	IntRect(152, 40, 16,  8)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
///* Cycling */
 | 
			
		||||
//static unsigned char cursorAniAlpha[] =
 | 
			
		||||
//{
 | 
			
		||||
//    /* Fade out */
 | 
			
		||||
//	0xFF, 0xF0, 0xE8, 0xE0, 0xD8, 0xD0, 0xC8, 0xC0,
 | 
			
		||||
//	0xB8, 0xB0, 0xA8, 0xA0, 0x98, 0x90, 0x88, 0x80,
 | 
			
		||||
//	/* Fade in */
 | 
			
		||||
//	0x78, 0x80, 0x88, 0x90, 0x98, 0xA0, 0xA8, 0xB0,
 | 
			
		||||
//    0xB8, 0xC0, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xF0
 | 
			
		||||
//};
 | 
			
		||||
 | 
			
		||||
static unsigned char cursorAniAlpha[] =
 | 
			
		||||
{
 | 
			
		||||
    /* Fade out */
 | 
			
		||||
	0xFF, 0xF7, 0xEF, 0xE7, 0xDF, 0xD7, 0xCF, 0xC7,
 | 
			
		||||
	0xBF, 0xB7, 0xAF, 0xA7, 0x9F, 0x97, 0x8F, 0x87,
 | 
			
		||||
	/* Fade in */
 | 
			
		||||
	0x7F, 0x87, 0x8F, 0x97, 0x9F, 0xA7, 0xAF, 0xB7,
 | 
			
		||||
    0xBF, 0xC7, 0xCF, 0xD7, 0xDF, 0xE7, 0xEF, 0xF7
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(cursorAniAlpha);
 | 
			
		||||
 | 
			
		||||
/* Cycling */
 | 
			
		||||
static unsigned char pauseAniQuad[] =
 | 
			
		||||
{
 | 
			
		||||
    0, 0, 0, 0, 0, 0, 0, 0,
 | 
			
		||||
    1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
    2, 2, 2, 2, 2, 2, 2, 2,
 | 
			
		||||
    3, 3, 3, 3, 3, 3, 3, 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(pauseAniQuad);
 | 
			
		||||
 | 
			
		||||
/* No cycle */
 | 
			
		||||
static unsigned char pauseAniAlpha[] =
 | 
			
		||||
{
 | 
			
		||||
    0x00, 0x20, 0x40, 0x60,
 | 
			
		||||
    0x80, 0xA0, 0xC0, 0xE0,
 | 
			
		||||
    0xFF
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static elementsN(pauseAniAlpha);
 | 
			
		||||
 | 
			
		||||
/* Points to an array of quads which it doesn't own.
 | 
			
		||||
 * Useful for setting alpha of quads stored inside
 | 
			
		||||
 * bigger arrays */
 | 
			
		||||
struct QuadChunk
 | 
			
		||||
{
 | 
			
		||||
	Vertex *vert;
 | 
			
		||||
	int count; /* In quads */
 | 
			
		||||
 | 
			
		||||
	QuadChunk()
 | 
			
		||||
	    : vert(0), count(0)
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
	void setAlpha(float value)
 | 
			
		||||
	{
 | 
			
		||||
		for (int i = 0; i < count*4; ++i)
 | 
			
		||||
			vert[i].color.w = value;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Vocabulary:
 | 
			
		||||
 *
 | 
			
		||||
 * Base: Base layer of window; includes background and borders.
 | 
			
		||||
 *   Drawn at z+0.
 | 
			
		||||
 *
 | 
			
		||||
 * Controls: Controls layer of window; includes scroll arrows,
 | 
			
		||||
 *   pause animation, cursor rectangle and contents bitmap.
 | 
			
		||||
 *   Drawn at z+2.
 | 
			
		||||
 *
 | 
			
		||||
 * Scroll arrows: Arrows that appear automatically when a part of
 | 
			
		||||
 *   the contents bitmap is not visible in either upper, lower, left
 | 
			
		||||
 *   or right direction.
 | 
			
		||||
 *
 | 
			
		||||
 * Pause: Animation that displays an animating icon in the bottom
 | 
			
		||||
 *   center of the window, usually indicating user input is awaited,
 | 
			
		||||
 *   such as when text is displayed.
 | 
			
		||||
 *
 | 
			
		||||
 * Cursor: Blinking rectangle that usually displays a selection to
 | 
			
		||||
 *   the user.
 | 
			
		||||
 *
 | 
			
		||||
 * Contents: User settable bitmap that is drawn inside the window,
 | 
			
		||||
 *   clipped to a 16 pixel smaller rectangle. Position is adjusted
 | 
			
		||||
 *   with OX/OY.
 | 
			
		||||
 *
 | 
			
		||||
 * BaseTex: If the window has an opacity <255, we have to prerender
 | 
			
		||||
 *   the base to a texture and draw that. Otherwise, we can draw the
 | 
			
		||||
 *   quad array directly to the screen.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct WindowPrivate
 | 
			
		||||
{
 | 
			
		||||
	Bitmap *windowskin;
 | 
			
		||||
	Bitmap *contents;
 | 
			
		||||
	bool bgStretch;
 | 
			
		||||
	Rect *cursorRect;
 | 
			
		||||
	bool active;
 | 
			
		||||
	bool pause;
 | 
			
		||||
 | 
			
		||||
	sigc::connection cursorRectCon;
 | 
			
		||||
 | 
			
		||||
	Vec2i sceneOffset;
 | 
			
		||||
 | 
			
		||||
	Vec2i position;
 | 
			
		||||
	Vec2i size;
 | 
			
		||||
	Vec2i contentsOffset;
 | 
			
		||||
 | 
			
		||||
	NormValue opacity;
 | 
			
		||||
	NormValue backOpacity;
 | 
			
		||||
	NormValue contentsOpacity;
 | 
			
		||||
 | 
			
		||||
	bool baseVertDirty;
 | 
			
		||||
	bool opacityDirty;
 | 
			
		||||
	bool baseTexDirty;
 | 
			
		||||
 | 
			
		||||
	ColorQuadArray baseQuadArray;
 | 
			
		||||
 | 
			
		||||
	/* Used when opacity < 255 */
 | 
			
		||||
	TexFBO baseTex;
 | 
			
		||||
	bool useBaseTex;
 | 
			
		||||
 | 
			
		||||
	QuadChunk backgroundVert;
 | 
			
		||||
 | 
			
		||||
	Quad baseTexQuad;
 | 
			
		||||
 | 
			
		||||
	struct WindowControls : public ViewportElement
 | 
			
		||||
	{
 | 
			
		||||
		WindowPrivate *p;
 | 
			
		||||
 | 
			
		||||
		WindowControls(WindowPrivate *p,
 | 
			
		||||
		               Viewport *viewport = 0)
 | 
			
		||||
		    : ViewportElement(viewport),
 | 
			
		||||
		      p(p)
 | 
			
		||||
		{
 | 
			
		||||
			setZ(2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void draw()
 | 
			
		||||
		{
 | 
			
		||||
			p->drawControls();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		void release()
 | 
			
		||||
		{
 | 
			
		||||
			unlink();
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	WindowControls controlsElement;
 | 
			
		||||
 | 
			
		||||
	ColorQuadArray controlsQuadArray;
 | 
			
		||||
	int controlsQuadCount;
 | 
			
		||||
 | 
			
		||||
	Quad contentsQuad;
 | 
			
		||||
 | 
			
		||||
	QuadChunk pauseAniVert;
 | 
			
		||||
	QuadChunk cursorVert;
 | 
			
		||||
 | 
			
		||||
	unsigned char cursorAniAlphaIdx;
 | 
			
		||||
	unsigned char pauseAniAlphaIdx;
 | 
			
		||||
	unsigned char pauseAniQuadIdx;
 | 
			
		||||
 | 
			
		||||
	bool controlsVertDirty;
 | 
			
		||||
 | 
			
		||||
	EtcTemps tmp;
 | 
			
		||||
 | 
			
		||||
	sigc::connection prepareCon;
 | 
			
		||||
 | 
			
		||||
	WindowPrivate(Viewport *viewport = 0)
 | 
			
		||||
	    : windowskin(0),
 | 
			
		||||
	      contents(0),
 | 
			
		||||
	      bgStretch(true),
 | 
			
		||||
	      cursorRect(&tmp.rect),
 | 
			
		||||
	      active(true),
 | 
			
		||||
	      pause(false),
 | 
			
		||||
	      opacity(255),
 | 
			
		||||
	      backOpacity(255),
 | 
			
		||||
	      contentsOpacity(255),
 | 
			
		||||
	      baseVertDirty(true),
 | 
			
		||||
	      opacityDirty(true),
 | 
			
		||||
	      baseTexDirty(true),
 | 
			
		||||
	      controlsElement(this, viewport),
 | 
			
		||||
	      cursorAniAlphaIdx(0),
 | 
			
		||||
	      pauseAniAlphaIdx(0),
 | 
			
		||||
	      pauseAniQuadIdx(0),
 | 
			
		||||
	      controlsVertDirty(true)
 | 
			
		||||
	{
 | 
			
		||||
		refreshCursorRectCon();
 | 
			
		||||
 | 
			
		||||
		controlsQuadArray.resize(14);
 | 
			
		||||
		TileQuads::buildFrameSource(cursorSrc, controlsQuadArray.vertices.data());
 | 
			
		||||
		cursorVert.count = 9;
 | 
			
		||||
		pauseAniVert.count = 1;
 | 
			
		||||
 | 
			
		||||
		prepareCon = gState->prepareDraw.connect
 | 
			
		||||
		        (sigc::mem_fun(this, &WindowPrivate::prepare));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~WindowPrivate()
 | 
			
		||||
	{
 | 
			
		||||
		gState->texPool().release(baseTex);
 | 
			
		||||
		cursorRectCon.disconnect();
 | 
			
		||||
		prepareCon.disconnect();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void onCursorRectChange()
 | 
			
		||||
	{
 | 
			
		||||
		controlsVertDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void refreshCursorRectCon()
 | 
			
		||||
	{
 | 
			
		||||
		cursorRectCon.disconnect();
 | 
			
		||||
		cursorRectCon = cursorRect->valueChanged.connect
 | 
			
		||||
		        (sigc::mem_fun(this, &WindowPrivate::onCursorRectChange));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void buildBaseVert()
 | 
			
		||||
	{
 | 
			
		||||
		int w = size.x;
 | 
			
		||||
		int h = size.y;
 | 
			
		||||
 | 
			
		||||
		IntRect bgRect(2, 2, w - 4, h - 4);
 | 
			
		||||
 | 
			
		||||
		Sides<IntRect> borderRects;
 | 
			
		||||
		borderRects.l = IntRect(0,    8,    16,   h-16);
 | 
			
		||||
		borderRects.r = IntRect(w-16, 8,    16,   h-16);
 | 
			
		||||
		borderRects.t = IntRect(8,    0,    w-16, 16  );
 | 
			
		||||
		borderRects.b = IntRect(8,    h-16, w-16, 16  );
 | 
			
		||||
 | 
			
		||||
		Corners<IntRect> cornerRects;
 | 
			
		||||
		cornerRects.tl = IntRect(0,    0,    16, 16);
 | 
			
		||||
		cornerRects.tr = IntRect(w-16, 0,    16, 16);
 | 
			
		||||
		cornerRects.bl = IntRect(0,    h-16, 16, 16);
 | 
			
		||||
		cornerRects.br = IntRect(w-16, h-16, 16, 16);
 | 
			
		||||
 | 
			
		||||
		/* Required quad count */
 | 
			
		||||
		int count = 0;
 | 
			
		||||
 | 
			
		||||
		/* Background */
 | 
			
		||||
		if (bgStretch)
 | 
			
		||||
			backgroundVert.count = 1;
 | 
			
		||||
		else
 | 
			
		||||
			backgroundVert.count =
 | 
			
		||||
			        TileQuads::twoDimCount(128, 128, bgRect.w, bgRect.h);
 | 
			
		||||
 | 
			
		||||
		count += backgroundVert.count;
 | 
			
		||||
 | 
			
		||||
		/* Borders (sides) */
 | 
			
		||||
		count += TileQuads::oneDimCount(32, w-16) * 2;
 | 
			
		||||
		count += TileQuads::oneDimCount(32, h-16) * 2;
 | 
			
		||||
 | 
			
		||||
		/* Corners */
 | 
			
		||||
		count += 4;
 | 
			
		||||
 | 
			
		||||
		/* Our vertex array */
 | 
			
		||||
		baseQuadArray.resize(count);
 | 
			
		||||
		Vertex *vert = baseQuadArray.vertices.data();
 | 
			
		||||
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		backgroundVert.vert = &vert[i];
 | 
			
		||||
 | 
			
		||||
		/* Background */
 | 
			
		||||
		if (bgStretch)
 | 
			
		||||
		{
 | 
			
		||||
			Quad::setTexRect(&vert[i*4], backgroundSrc);
 | 
			
		||||
			Quad::setPosRect(&vert[i*4], bgRect);
 | 
			
		||||
			i += 1;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			i += TileQuads::build(backgroundSrc, bgRect, &vert[i*4]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Borders */
 | 
			
		||||
		i += TileQuads::buildH(bordersSrc.t, w-16, 8,    0,    &vert[i*4]);
 | 
			
		||||
		i += TileQuads::buildH(bordersSrc.b, w-16, 8,    h-16, &vert[i*4]);
 | 
			
		||||
		i += TileQuads::buildV(bordersSrc.l, h-16, 0,    8,    &vert[i*4]);
 | 
			
		||||
		i += TileQuads::buildV(bordersSrc.r, h-16, w-16, 8,    &vert[i*4]);
 | 
			
		||||
 | 
			
		||||
		/* Corners */
 | 
			
		||||
		i += Quad::setTexPosRect(&vert[i*4], cornersSrc.tl, cornerRects.tl);
 | 
			
		||||
		i += Quad::setTexPosRect(&vert[i*4], cornersSrc.tr, cornerRects.tr);
 | 
			
		||||
		i += Quad::setTexPosRect(&vert[i*4], cornersSrc.bl, cornerRects.bl);
 | 
			
		||||
		i += Quad::setTexPosRect(&vert[i*4], cornersSrc.br, cornerRects.br);
 | 
			
		||||
 | 
			
		||||
		for (int j = 0; j < count*4; ++j)
 | 
			
		||||
			vert[j].color = Vec4(1, 1, 1, 1);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		FloatRect texRect = FloatRect(0, 0, size.x, size.y);
 | 
			
		||||
		baseTexQuad.setTexPosRect(texRect, texRect);
 | 
			
		||||
 | 
			
		||||
		baseTexDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateBaseAlpha()
 | 
			
		||||
	{
 | 
			
		||||
		/* This is always applied unconditionally */
 | 
			
		||||
		backgroundVert.setAlpha(backOpacity.norm);
 | 
			
		||||
 | 
			
		||||
		baseTexQuad.setColor(Vec4(1, 1, 1, opacity.norm));
 | 
			
		||||
 | 
			
		||||
		baseTexDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void ensureBaseTexReady()
 | 
			
		||||
	{
 | 
			
		||||
		/* Make sure texture is big enough */
 | 
			
		||||
		int newW = baseTex.width;
 | 
			
		||||
		int newH = baseTex.height;
 | 
			
		||||
		bool resizeNeeded = false;
 | 
			
		||||
 | 
			
		||||
		if (size.x > baseTex.width)
 | 
			
		||||
		{
 | 
			
		||||
			newW = findNextPow2(size.x);
 | 
			
		||||
			resizeNeeded = true;
 | 
			
		||||
		}
 | 
			
		||||
		if (size.y > baseTex.height)
 | 
			
		||||
		{
 | 
			
		||||
			newH = findNextPow2(size.y);
 | 
			
		||||
			resizeNeeded = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!resizeNeeded)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		gState->texPool().release(baseTex);
 | 
			
		||||
		baseTex = gState->texPool().request(newW, newH);
 | 
			
		||||
 | 
			
		||||
		qDebug() << "Allocated bg tex:" << newW << newH;
 | 
			
		||||
 | 
			
		||||
		baseTexDirty = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void redrawBaseTex()
 | 
			
		||||
	{
 | 
			
		||||
		/* Discard old buffer */
 | 
			
		||||
		Tex::bind(baseTex.tex);
 | 
			
		||||
		Tex::allocEmpty(baseTex.width, baseTex.height);
 | 
			
		||||
		Tex::unbind();
 | 
			
		||||
 | 
			
		||||
		FBO::bind(baseTex.fbo);
 | 
			
		||||
		glState.pushSetViewport(baseTex.width, baseTex.height);
 | 
			
		||||
		glState.clearColor.pushSet(Vec4());
 | 
			
		||||
 | 
			
		||||
		/* Clear texture */
 | 
			
		||||
		glClear(GL_COLOR_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
		/* Repaint base */
 | 
			
		||||
		windowskin->flush();
 | 
			
		||||
		windowskin->bindTexWithMatrix();
 | 
			
		||||
		Tex::setSmooth(true);
 | 
			
		||||
		glState.pushSetViewport(baseTex.width, baseTex.height);
 | 
			
		||||
 | 
			
		||||
		/* We need to blit the background without blending,
 | 
			
		||||
		 * because we want to retain its correct alpha value.
 | 
			
		||||
		 * Otherwise it would be mutliplied by the backgrounds 0 alpha */
 | 
			
		||||
		glState.blendMode.pushSet(BlendNone);
 | 
			
		||||
 | 
			
		||||
		baseQuadArray.draw(0, backgroundVert.count);
 | 
			
		||||
 | 
			
		||||
		/* Now draw the rest (ie. the frame) with blending */
 | 
			
		||||
		glState.blendMode.set(BlendNormal);
 | 
			
		||||
 | 
			
		||||
		baseQuadArray.draw(backgroundVert.count, baseQuadArray.count()-backgroundVert.count);
 | 
			
		||||
 | 
			
		||||
		glState.blendMode.pop();
 | 
			
		||||
		glState.popViewport();
 | 
			
		||||
		Tex::setSmooth(false);
 | 
			
		||||
 | 
			
		||||
		glState.clearColor.pop();
 | 
			
		||||
		glState.popViewport();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void buildControlsVert()
 | 
			
		||||
	{
 | 
			
		||||
		int i = 0;
 | 
			
		||||
		Vertex *vert = controlsQuadArray.vertices.data();
 | 
			
		||||
 | 
			
		||||
		/* Cursor */
 | 
			
		||||
		if (!cursorRect->isEmpty())
 | 
			
		||||
		{
 | 
			
		||||
			/* Effective cursor rect has 16 xy offset to window */
 | 
			
		||||
			IntRect effectRect(cursorRect->x+16, cursorRect->y+16,
 | 
			
		||||
			                   cursorRect->width, cursorRect->height);
 | 
			
		||||
			cursorVert.vert = &vert[i*4];
 | 
			
		||||
			i += TileQuads::buildFrame(effectRect, &vert[i*4]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Scroll arrows */
 | 
			
		||||
		int scrollLRY = (size.y - 16) / 2;
 | 
			
		||||
		int scrollTBX = (size.x - 16) / 2;
 | 
			
		||||
 | 
			
		||||
		Sides<IntRect> scrollArrows;
 | 
			
		||||
 | 
			
		||||
		scrollArrows.l = IntRect(4, scrollLRY, 8, 16);
 | 
			
		||||
		scrollArrows.r = IntRect(size.x - 12, scrollLRY, 8, 16);
 | 
			
		||||
		scrollArrows.t = IntRect(scrollTBX, 4, 16, 8);
 | 
			
		||||
		scrollArrows.b = IntRect(scrollTBX, size.y - 12, 16, 8);
 | 
			
		||||
 | 
			
		||||
		if (contents)
 | 
			
		||||
		{
 | 
			
		||||
			if (contentsOffset.x > 0)
 | 
			
		||||
				i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.l, scrollArrows.l);
 | 
			
		||||
 | 
			
		||||
			if (contentsOffset.y > 0)
 | 
			
		||||
				i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.t, scrollArrows.t);
 | 
			
		||||
 | 
			
		||||
			if ((size.x - 32) < (contents->width() - contentsOffset.x))
 | 
			
		||||
				i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.r, scrollArrows.r);
 | 
			
		||||
 | 
			
		||||
			if ((size.y - 32) < (contents->height() - contentsOffset.y))
 | 
			
		||||
				i += Quad::setTexPosRect(&vert[i*4], scrollArrowSrc.b, scrollArrows.b);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Pause animation */
 | 
			
		||||
		if (pause)
 | 
			
		||||
		{
 | 
			
		||||
			pauseAniVert.vert = &vert[i*4];
 | 
			
		||||
			i += Quad::setTexPosRect(&vert[i*4], pauseAniSrc[pauseAniQuad[pauseAniQuadIdx]],
 | 
			
		||||
			                             FloatRect((size.x - 16) / 2, size.y - 16, 16, 16));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		controlsQuadArray.commit();
 | 
			
		||||
		controlsQuadCount = i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void prepare()
 | 
			
		||||
	{
 | 
			
		||||
		bool updateBaseQuadArray = false;
 | 
			
		||||
 | 
			
		||||
		if (baseVertDirty)
 | 
			
		||||
		{
 | 
			
		||||
			buildBaseVert();
 | 
			
		||||
			baseVertDirty = false;
 | 
			
		||||
			updateBaseQuadArray = true;
 | 
			
		||||
		}
 | 
			
		||||
		if (opacityDirty)
 | 
			
		||||
		{
 | 
			
		||||
			updateBaseAlpha();
 | 
			
		||||
			opacityDirty = false;
 | 
			
		||||
			updateBaseQuadArray = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (updateBaseQuadArray)
 | 
			
		||||
			baseQuadArray.commit();
 | 
			
		||||
 | 
			
		||||
		/* If opacity has effect, we must prerender to a texture
 | 
			
		||||
		 * and then draw this texture instead of the quad array */
 | 
			
		||||
		useBaseTex = opacity < 255;
 | 
			
		||||
 | 
			
		||||
		if (useBaseTex)
 | 
			
		||||
		{
 | 
			
		||||
			ensureBaseTexReady();
 | 
			
		||||
 | 
			
		||||
			if (baseTexDirty)
 | 
			
		||||
			{
 | 
			
		||||
				redrawBaseTex();
 | 
			
		||||
				baseTexDirty = false;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void drawBase()
 | 
			
		||||
	{
 | 
			
		||||
		if (!windowskin)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (size == Vec2i(0, 0))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		glPushMatrix();
 | 
			
		||||
		glLoadIdentity();
 | 
			
		||||
		glTranslatef(position.x + sceneOffset.x,
 | 
			
		||||
		             position.y + sceneOffset.y, 0);
 | 
			
		||||
 | 
			
		||||
		if (useBaseTex)
 | 
			
		||||
		{
 | 
			
		||||
			Tex::bindWithMatrix(baseTex.tex, baseTex.width, baseTex.height);
 | 
			
		||||
			baseTexQuad.draw();
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			windowskin->flush();
 | 
			
		||||
			windowskin->bindTexWithMatrix();
 | 
			
		||||
			Tex::setSmooth(true);
 | 
			
		||||
 | 
			
		||||
			baseQuadArray.draw();
 | 
			
		||||
 | 
			
		||||
			Tex::setSmooth(false);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		glPopMatrix();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void drawControls()
 | 
			
		||||
	{
 | 
			
		||||
		if (!windowskin)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (size == Vec2i(0, 0))
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		if (controlsVertDirty)
 | 
			
		||||
		{
 | 
			
		||||
			buildControlsVert();
 | 
			
		||||
			updateControls();
 | 
			
		||||
			controlsVertDirty = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* Actual on screen coordinates */
 | 
			
		||||
		int effectX = position.x + sceneOffset.x;
 | 
			
		||||
		int effectY = position.y + sceneOffset.y;
 | 
			
		||||
 | 
			
		||||
		glPushMatrix();
 | 
			
		||||
		glLoadIdentity();
 | 
			
		||||
		glTranslatef(effectX, effectY, 0);
 | 
			
		||||
 | 
			
		||||
		IntRect windowRect(effectX, effectY, size.x, size.y);
 | 
			
		||||
		IntRect contentsRect(effectX+16, effectY+16, size.x-32, size.y-32);
 | 
			
		||||
 | 
			
		||||
		glState.scissorTest.pushSet(true);
 | 
			
		||||
		glState.scissorBox.push();
 | 
			
		||||
		glState.scissorBox.setIntersect(windowRect);
 | 
			
		||||
 | 
			
		||||
		/* Draw arrows / cursors */
 | 
			
		||||
		windowskin->bindTexWithMatrix();
 | 
			
		||||
		controlsQuadArray.draw(0, controlsQuadCount);
 | 
			
		||||
 | 
			
		||||
		if (contents)
 | 
			
		||||
		{
 | 
			
		||||
			/* Draw contents bitmap */
 | 
			
		||||
			glState.scissorBox.setIntersect(contentsRect);
 | 
			
		||||
			glTranslatef(16-contentsOffset.x, 16-contentsOffset.y, 0);
 | 
			
		||||
 | 
			
		||||
			contents->flush();
 | 
			
		||||
			contents->bindTexWithMatrix();
 | 
			
		||||
			contentsQuad.draw();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		glState.scissorBox.pop();
 | 
			
		||||
		glState.scissorTest.pop();
 | 
			
		||||
		glPopMatrix();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void updateControls()
 | 
			
		||||
	{
 | 
			
		||||
		bool updateArray = false;
 | 
			
		||||
 | 
			
		||||
		if (active && cursorVert.vert)
 | 
			
		||||
		{
 | 
			
		||||
			float alpha = cursorAniAlpha[cursorAniAlphaIdx] / 255.0;
 | 
			
		||||
 | 
			
		||||
			cursorVert.setAlpha(alpha);
 | 
			
		||||
 | 
			
		||||
			updateArray = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (pause && pauseAniVert.vert)
 | 
			
		||||
		{
 | 
			
		||||
			float alpha = pauseAniAlpha[pauseAniAlphaIdx] / 255.0;
 | 
			
		||||
			FloatRect frameRect = pauseAniSrc[pauseAniQuad[pauseAniQuadIdx]];
 | 
			
		||||
 | 
			
		||||
			pauseAniVert.setAlpha(alpha);
 | 
			
		||||
			Quad::setTexRect(pauseAniVert.vert, frameRect);
 | 
			
		||||
 | 
			
		||||
			updateArray = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (updateArray)
 | 
			
		||||
			controlsQuadArray.commit();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void stepAnimations()
 | 
			
		||||
	{
 | 
			
		||||
		if (++cursorAniAlphaIdx == cursorAniAlphaN)
 | 
			
		||||
			cursorAniAlphaIdx = 0;
 | 
			
		||||
 | 
			
		||||
		if (pauseAniAlphaIdx < pauseAniAlphaN-1)
 | 
			
		||||
			++pauseAniAlphaIdx;
 | 
			
		||||
 | 
			
		||||
		if (++pauseAniQuadIdx == pauseAniQuadN)
 | 
			
		||||
			pauseAniQuadIdx = 0;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Window::Window(Viewport *viewport)
 | 
			
		||||
	: ViewportElement(viewport)
 | 
			
		||||
{
 | 
			
		||||
	p = new WindowPrivate(viewport);
 | 
			
		||||
	onGeometryChange(scene->getGeometry());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Window::~Window()
 | 
			
		||||
{
 | 
			
		||||
	dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::update()
 | 
			
		||||
{
 | 
			
		||||
	p->updateControls();
 | 
			
		||||
	p->stepAnimations();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DISP_CLASS_NAME "window"
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_SIMPLE(Window, Windowskin, Bitmap*, p->windowskin)
 | 
			
		||||
DEF_ATTR_SIMPLE(Window, X,          int,     p->position.x)
 | 
			
		||||
DEF_ATTR_SIMPLE(Window, Y,          int,     p->position.y)
 | 
			
		||||
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Contents,        Bitmap*, p->contents)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Stretch,         bool,    p->bgStretch)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, CursorRect,      Rect*,   p->cursorRect)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Active,          bool,    p->active)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Pause,           bool,    p->pause)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Width,           int,     p->size.x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Height,          int,     p->size.y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, OX,              int,     p->contentsOffset.x)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, OY,              int,     p->contentsOffset.y)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, Opacity,         int,     p->opacity)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, BackOpacity,     int,     p->backOpacity)
 | 
			
		||||
DEF_ATTR_RD_SIMPLE(Window, ContentsOpacity, int,     p->contentsOpacity)
 | 
			
		||||
 | 
			
		||||
void Window::setContents(Bitmap *value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	p->contents = value;
 | 
			
		||||
	p->controlsVertDirty = true;
 | 
			
		||||
 | 
			
		||||
	if (value)
 | 
			
		||||
		p->contentsQuad.setTexPosRect(value->rect(), value->rect());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setStretch(bool value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (value == p->bgStretch)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->bgStretch = value;
 | 
			
		||||
	p->baseVertDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setCursorRect(Rect *value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->cursorRect == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->cursorRect = value;
 | 
			
		||||
 | 
			
		||||
	p->refreshCursorRectCon();
 | 
			
		||||
	p->onCursorRectChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setActive(bool value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->active == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->active = value;
 | 
			
		||||
	p->cursorAniAlphaIdx = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setPause(bool value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->pause == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->pause = value;
 | 
			
		||||
	p->pauseAniAlphaIdx = 0;
 | 
			
		||||
	p->pauseAniQuadIdx = 0;
 | 
			
		||||
	p->controlsVertDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setWidth(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->size.x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->size.x = value;
 | 
			
		||||
	p->baseVertDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setHeight(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->size.y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->size.y = value;
 | 
			
		||||
	p->baseVertDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setOX(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->contentsOffset.x == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->contentsOffset.x = value;
 | 
			
		||||
	p->controlsVertDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setOY(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->contentsOffset.y == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->contentsOffset.y = value;
 | 
			
		||||
	p->controlsVertDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setOpacity(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->opacity == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->opacity = value;
 | 
			
		||||
	p->opacityDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setBackOpacity(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->backOpacity == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->backOpacity = value;
 | 
			
		||||
	p->opacityDirty = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setContentsOpacity(int value)
 | 
			
		||||
{
 | 
			
		||||
	GUARD_DISPOSED
 | 
			
		||||
 | 
			
		||||
	if (p->contentsOpacity == value)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	p->contentsOpacity = value;
 | 
			
		||||
	p->contentsQuad.setColor(Vec4(1, 1, 1, p->contentsOpacity.norm));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::draw()
 | 
			
		||||
{
 | 
			
		||||
	p->drawBase();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::onGeometryChange(const Scene::Geometry &geo)
 | 
			
		||||
{
 | 
			
		||||
	p->sceneOffset.x = geo.rect.x - geo.xOrigin;
 | 
			
		||||
	p->sceneOffset.y = geo.rect.y - geo.yOrigin;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setZ(int value)
 | 
			
		||||
{
 | 
			
		||||
	ViewportElement::setZ(value);
 | 
			
		||||
 | 
			
		||||
	p->controlsElement.setZ(value + 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::setVisible(bool value)
 | 
			
		||||
{
 | 
			
		||||
	ViewportElement::setVisible(value);
 | 
			
		||||
 | 
			
		||||
	p->controlsElement.setVisible(value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::onViewportChange()
 | 
			
		||||
{
 | 
			
		||||
	p->controlsElement.setScene(*this->scene);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Window::releaseResources()
 | 
			
		||||
{
 | 
			
		||||
	p->controlsElement.release();
 | 
			
		||||
 | 
			
		||||
	unlink();
 | 
			
		||||
 | 
			
		||||
	delete p;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								src/window.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/window.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,72 @@
 | 
			
		|||
/*
 | 
			
		||||
** window.h
 | 
			
		||||
**
 | 
			
		||||
** This file is part of mkxp.
 | 
			
		||||
**
 | 
			
		||||
** Copyright (C) 2013 Jonas Kulla <Nyocurio@gmail.com>
 | 
			
		||||
**
 | 
			
		||||
** mkxp is free software: you can redistribute it and/or modify
 | 
			
		||||
** it under the terms of the GNU General Public License as published by
 | 
			
		||||
** the Free Software Foundation, either version 2 of the License, or
 | 
			
		||||
** (at your option) any later version.
 | 
			
		||||
**
 | 
			
		||||
** mkxp is distributed in the hope that it will be useful,
 | 
			
		||||
** but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
** GNU General Public License for more details.
 | 
			
		||||
**
 | 
			
		||||
** You should have received a copy of the GNU General Public License
 | 
			
		||||
** along with mkxp.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef WINDOW_H
 | 
			
		||||
#define WINDOW_H
 | 
			
		||||
 | 
			
		||||
#include "viewport.h"
 | 
			
		||||
#include "disposable.h"
 | 
			
		||||
 | 
			
		||||
#include "util.h"
 | 
			
		||||
 | 
			
		||||
class Bitmap;
 | 
			
		||||
struct Rect;
 | 
			
		||||
 | 
			
		||||
struct WindowPrivate;
 | 
			
		||||
 | 
			
		||||
class Window : public ViewportElement, public Disposable
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	Window(Viewport *viewport = 0);
 | 
			
		||||
	~Window();
 | 
			
		||||
 | 
			
		||||
	void update();
 | 
			
		||||
 | 
			
		||||
	DECL_ATTR( Windowskin,      Bitmap* )
 | 
			
		||||
	DECL_ATTR( Contents,        Bitmap* )
 | 
			
		||||
	DECL_ATTR( Stretch,         bool    )
 | 
			
		||||
	DECL_ATTR( CursorRect,      Rect*   )
 | 
			
		||||
	DECL_ATTR( Active,          bool    )
 | 
			
		||||
	DECL_ATTR( Pause,           bool    )
 | 
			
		||||
	DECL_ATTR( X,               int     )
 | 
			
		||||
	DECL_ATTR( Y,               int     )
 | 
			
		||||
	DECL_ATTR( Width,           int     )
 | 
			
		||||
	DECL_ATTR( Height,          int     )
 | 
			
		||||
	DECL_ATTR( OX,              int     )
 | 
			
		||||
	DECL_ATTR( OY,              int     )
 | 
			
		||||
	DECL_ATTR( Opacity,         int     )
 | 
			
		||||
	DECL_ATTR( BackOpacity,     int     )
 | 
			
		||||
	DECL_ATTR( ContentsOpacity, int     )
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	WindowPrivate *p;
 | 
			
		||||
 | 
			
		||||
	void draw();
 | 
			
		||||
	void onGeometryChange(const Scene::Geometry &);
 | 
			
		||||
	void setZ(int value);
 | 
			
		||||
	void setVisible(bool value);
 | 
			
		||||
 | 
			
		||||
	void onViewportChange();
 | 
			
		||||
 | 
			
		||||
	void releaseResources();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // WINDOW_H
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue