diff --git a/Modding.txt b/Modding.txt new file mode 100644 index 0000000..a53b484 --- /dev/null +++ b/Modding.txt @@ -0,0 +1,171 @@ +Clonepoint loads maps from .tmx files generated by the Tiled Editor. You +can obtain the editor here. + +http://www.mapeditor.org/ + +Notes on making maps for Clonepoint: + +- If you want to test your maps quickly, compile Clonepoint with the +-DDEBUG flag to allow you to teleport to the mouse's position with +the middle mouse button. + +- Clonepoint considers all files in the data/ directory with the .tmx +extension as potential maps to load. + +- It is highly recommended that you copy one of the existing maps and +use them as a template to quickly make new ones. template.tmx contains +all entities you need to copy into other maps as well. + +- Don't make a map called template.tmx - Clonepoint discards this as +a potential map to load. + +- Clonepoint only loads entities and collision volumes if they are in +the correct Object Group. + +- There are no "collision" tiles, but collision volumes. To use them, +create rectangles in the "Collision" object group. + + * To make glass volumes, make a collision volume with the type field as + "Glass". Glass volumes can be of any dimension, but the standard I use + is 4 pixels (or 0.25 units) for width or height. + + * To make invisible volumes that only block enemies (used to keep them + from leaving a building and patrolling the end of the map), create a + collision volume with the type field as "GuardBlock". + +- To add other entities with graphics, you can use Tile's "Insert Tile (T)" +feature to add a graphical representation of them in the editor. This is +for your convenience. Clonepoint's level loading function doesn't care +about what graphics you choose, but rather what "type" the object is in +the editor. If an entity you added in the editor is not appearing in the +game, make sure you wrote in the type for the entity and put it in the +right object group. + +- To add guards, circuit boxes, and stairs, add them in the "Entity" object +group. + + * Guards have type "Guard". Enforcers have type "Enforcer". Professionals + have type "Professional". + + * By default, created enemies face left. To make them face right, add a + custom property called "direction" with the value "right". + + * By default, created enemies stand still. To make them patrol, add a + custom property called "patrolling" with the value "yes". + +- To add stairs, add entities with the type "Stairs" in the "Entity" +object group. + + * To create stairwells, just create stairs with the same x position. + +- To create circuit boxes that unlock a particlar circuit in the map, create +an entity in the "Entity" object group with the following names in the type +property. + + * CircuitBoxG - Green + * CircuitBoxV - Violet + * CircuitBoxY - Yellow + * CircuitBoxB - Blue + +- To create a spawn point for the player, add an entity with the type "Player" +in the "Player" object group. Creating multiple spawn points will cause the +player to be spawned in the last point. + +- To add props in the map that serve no gameplay purpose, create them in the +"Props" object group. There are a few names you can write in the type property +to get a valid prop. + + * Watercooler + * Shelf + * Trashcan + * Couch + * Plant1 + * Plant2 + * LightPanel + +- To create objectives in the map, add entities with the type "Terminal" in the +"Objectives" object group. + + * If no Terminals are found, the player can simply go to the exit to complete + the map. + +- To create the subway entrance where the player can exit the map, create an entity +with the type "Subway" in the "Objectives" object group. + + * Creating multiple subways will simply spawn one subway in the last location added. + + * If no subways are found, the player may exit the map by going to the right + boundary of the map. + +- To create linkable objects, create entities in the following object groups + + * RedLinkable - for objects in the Red circuit. + * BlueLinkable - for objects in the Blue circuit. + * VioletLinkable - for objects in the Violet circuit. + * YellowLinkable - for objects in the Yellow circuit. + * GreenLinkable - for objects in the Green circuit. + +- The following linkable objects may be added by writing in the correct name +in the "type" property and adding them in the previous object groups. + + * Alarm + * SoundDetector + * TrapDoor + * Elevator + + To create elevator shafts, just create Elevators with the same x position. + * Switch + + To create handscanners, create a switch with a custom property "handscanner" as + "yes". + * VaultDoor + * Socket + * Scanner + * Door + + By default, Doors spawn closed. To make them spawn opened, create a custom property + "open" with the value "yes". + * SecurityCamera + + By default, SecurityCameras spawn facing left. To make them spawn facing right, create + a custom property "direction" with the value "right". + * LightFixture + +- To make LightFixtures control other lights, perform the following actions. + + * Create a entity with the "type" property "Light" in the "Lights" object group. + + * Create a "polyline" (press L) object that goes from a LightFixture to the Light + in the "LightLinks" object group. Remember to right click after the link is made to + disable polyline creation. + +- To make lights that are not controlled by a LightFixture, simply create a light in the +"Lights" object group without a LightFixture linking to it. + + * By default, Lights emit light from all angles. To limit the number of angles, create + the custom property "numangles" with the value in degrees. + +- To make linkable objects link to others when the map starts, perform the following action. + + * Create a "polyline" (press L) object that goes from a linkable object to another in + the "Links" object group. + + * Only objects in the same circuit will actually be linked when the map starts. + +* To make a tilemap of graphics in the map, select the "Tile Layer 1" layer. + + * The data encoding for the tile layer MUST be in CSV format. + + * The "firstgid" property of this tileset MUST be 1. Multiple tilesets for a map + are not supported. + +* There are other map properties you can set in the "Map Properties" area. They are: + + * startingupgrades - The number of upgrades you want the player to start with when + upgrading jump power and time to charge jump. + + * startingenergy - The starting energy the player has to perform certain actions. + Currently, the only energy-spending action available is linking between enemy guns. + If not set, starting energy is zero. + + * startingammo - The starting ammo the player has for their weapon. If not set, starting + ammo is zero. + + * timetosniper - The number of seconds the player has after firing their weapon before + the police sniper arrives. If not set, time to sniper is 1 second. \ No newline at end of file diff --git a/VeraMono.txt b/VeraMono.txt new file mode 100644 index 0000000..e651be1 --- /dev/null +++ b/VeraMono.txt @@ -0,0 +1,124 @@ +Bitstream Vera Fonts Copyright + +The fonts have a generous copyright, allowing derivative works (as +long as "Bitstream" or "Vera" are not in the names), and full +redistribution (so long as they are not *sold* by themselves). They +can be be bundled, redistributed and sold with any software. + +The fonts are distributed under the following copyright: + +Copyright +========= + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream +Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute +the Font Software, including without limitation the rights to use, +copy, merge, publish, distribute, and/or sell copies of the Font +Software, and to permit persons to whom the Font Software is furnished +to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font +Software without prior written authorization from the Gnome Foundation +or Bitstream Inc., respectively. For further information, contact: +fonts at gnome dot org. + +Copyright FAQ +============= + + 1. I don't understand the resale restriction... What gives? + + Bitstream is giving away these fonts, but wishes to ensure its + competitors can't just drop the fonts as is into a font sale system + and sell them as is. It seems fair that if Bitstream can't make money + from the Bitstream Vera fonts, their competitors should not be able to + do so either. You can sell the fonts as part of any software package, + however. + + 2. I want to package these fonts separately for distribution and + sale as part of a larger software package or system. Can I do so? + + Yes. A RPM or Debian package is a "larger software package" to begin + with, and you aren't selling them independently by themselves. + See 1. above. + + 3. Are derivative works allowed? + Yes! + + 4. Can I change or add to the font(s)? + Yes, but you must change the name(s) of the font(s). + + 5. Under what terms are derivative works allowed? + + You must change the name(s) of the fonts. This is to ensure the + quality of the fonts, both to protect Bitstream and Gnome. We want to + ensure that if an application has opened a font specifically of these + names, it gets what it expects (though of course, using fontconfig, + substitutions could still could have occurred during font + opening). You must include the Bitstream copyright. Additional + copyrights can be added, as per copyright law. Happy Font Hacking! + + 6. If I have improvements for Bitstream Vera, is it possible they might get + adopted in future versions? + + Yes. The contract between the Gnome Foundation and Bitstream has + provisions for working with Bitstream to ensure quality additions to + the Bitstream Vera font family. Please contact us if you have such + additions. Note, that in general, we will want such additions for the + entire family, not just a single font, and that you'll have to keep + both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add + glyphs to the font, they must be stylistically in keeping with Vera's + design. Vera cannot become a "ransom note" font. Jim Lyles will be + providing a document describing the design elements used in Vera, as a + guide and aid for people interested in contributing to Vera. + + 7. I want to sell a software package that uses these fonts: Can I do so? + + Sure. Bundle the fonts with your software and sell your software + with the fonts. That is the intent of the copyright. + + 8. If applications have built the names "Bitstream Vera" into them, + can I override this somehow to use fonts of my choosing? + + This depends on exact details of the software. Most open source + systems and software (e.g., Gnome, KDE, etc.) are now converting to + use fontconfig (see www.fontconfig.org) to handle font configuration, + selection and substitution; it has provisions for overriding font + names and subsituting alternatives. An example is provided by the + supplied local.conf file, which chooses the family Bitstream Vera for + "sans", "serif" and "monospace". Other software (e.g., the XFree86 + core server) has other mechanisms for font substitution. + diff --git a/animations.cpp b/animations.cpp new file mode 100644 index 0000000..947e3b2 --- /dev/null +++ b/animations.cpp @@ -0,0 +1,117 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include "animations.h" + +AnimationManager::AnimationManager() +{ + _sequences[ANIM_PLAYER_RUNNING].reset(new AnimationSequence(true)); + _sequences[ANIM_PLAYER_RUNNING]->readFromFile("./data/animations/player_run.anim"); + + _sequences[ANIM_PLAYER_WALKING_AIMING].reset(new AnimationSequence(true)); + _sequences[ANIM_PLAYER_WALKING_AIMING]->readFromFile("./data/animations/player_walk_aiming.anim"); + + _sequences[ANIM_PLAYER_CLIMBING_UP].reset(new AnimationSequence(true)); + _sequences[ANIM_PLAYER_CLIMBING_UP]->readFromFile("./data/animations/player_climb_up.anim"); + + _sequences[ANIM_PLAYER_CEILING].reset(new AnimationSequence(true)); + _sequences[ANIM_PLAYER_CEILING]->readFromFile("./data/animations/player_ceiling.anim"); + + _sequences[ANIM_PLAYER_HACKING].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_HACKING]->readFromFile("./data/animations/player_hack_terminal.anim"); + + _sequences[ANIM_PLAYER_ATTACH_DOWN].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_ATTACH_DOWN]->readFromFile("./data/animations/player_attach_down.anim"); + + _sequences[ANIM_PLAYER_REACH_ROOF].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_REACH_ROOF]->readFromFile("./data/animations/player_reach_roof.anim"); + + _sequences[ANIM_PLAYER_ATTACH_TO_CEILING].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_ATTACH_TO_CEILING]->readFromFile("./data/animations/player_attach_to_ceiling.anim"); + + _sequences[ANIM_PLAYER_ATTACH_FROM_CEILING].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_ATTACH_FROM_CEILING]->readFromFile("./data/animations/player_attach_from_ceiling.anim"); + + _sequences[ANIM_PLAYER_ENTER_STAIRS].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_ENTER_STAIRS]->readFromFile("./data/animations/player_enter_stairs.anim"); + + _sequences[ANIM_PLAYER_EXIT_STAIRS].reset(new AnimationSequence(false)); + _sequences[ANIM_PLAYER_EXIT_STAIRS]->readFromFile("./data/animations/player_exit_stairs.anim"); + + _sequences[ANIM_ENEMY_PATROLLING].reset(new AnimationSequence(true)); + _sequences[ANIM_ENEMY_PATROLLING]->readFromFile("./data/animations/enemy_patrolling.anim"); + + _sequences[ANIM_ENEMY_PLAYER_STRUGGLE].reset(new AnimationSequence(true)); + _sequences[ANIM_ENEMY_PLAYER_STRUGGLE]->readFromFile("./data/animations/enemy_player_struggle.anim"); + + _sequences[ANIM_ENEMY_KNOCK_OUT].reset(new AnimationSequence(false)); + _sequences[ANIM_ENEMY_KNOCK_OUT]->readFromFile("./data/animations/enemy_punch_out.anim"); + + _sequences[ANIM_ENEMY_ENTER_STAIRS].reset(new AnimationSequence(false)); + _sequences[ANIM_ENEMY_ENTER_STAIRS]->readFromFile("./data/animations/enemy_enter_stairs.anim"); + + _sequences[ANIM_ENEMY_EXIT_STAIRS].reset(new AnimationSequence(false)); + _sequences[ANIM_ENEMY_EXIT_STAIRS]->readFromFile("./data/animations/enemy_exit_stairs.anim"); + + _sequences[ANIM_VAULT_OPEN].reset(new AnimationSequence(false)); + _sequences[ANIM_VAULT_OPEN]->readFromFile("./data/animations/vault_open.anim"); + + _sequences[ANIM_VAULT_CLOSE].reset(new AnimationSequence(false)); + _sequences[ANIM_VAULT_CLOSE]->readFromFile("./data/animations/vault_close.anim"); + + _sequences[ANIM_ALARM_ACTIVE].reset(new AnimationSequence(true)); + _sequences[ANIM_ALARM_ACTIVE]->readFromFile("./data/animations/alarm_active.anim"); + + _sequences[ANIM_ELEVATOR_CLOSE].reset(new AnimationSequence(false)); + _sequences[ANIM_ELEVATOR_CLOSE]->readFromFile("./data/animations/elevator_close.anim"); + + _sequences[ANIM_ELEVATOR_OPEN].reset(new AnimationSequence(false)); + _sequences[ANIM_ELEVATOR_OPEN]->readFromFile("./data/animations/elevator_open.anim"); +} + +AnimationManager::~AnimationManager() +{ +} + +AnimationSequence* AnimationManager::getSequence(eAnimations index) +{ + return _sequences[index].get(); +} + +unsigned int AnimationManager::getNextSprite(AnimationSequence* sequence, unsigned int* index, float* timeLeft, unsigned int dT, bool* finished) +{ + *finished = false; + *timeLeft -= dT; + + if (*timeLeft <= 0.0f) + { + *timeLeft = sequence->getMsPerFrame(); + *index = *index + 1; + if (*index >= sequence->getNumSprites()) + { + *index = 0; + if (!sequence->isLooping()) + { + *finished = true; + } + } + } + + return sequence->getSpriteAt(*index); +} \ No newline at end of file diff --git a/animations.h b/animations.h new file mode 100644 index 0000000..f8c5962 --- /dev/null +++ b/animations.h @@ -0,0 +1,64 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#ifndef ANIMATIONS_H +#define ANIMATIONS_H + +#include + +#include "sprite.h" + +enum eAnimations +{ + ANIM_PLAYER_RUNNING = 0, + ANIM_PLAYER_WALKING_AIMING, + ANIM_PLAYER_CLIMBING_UP, + ANIM_PLAYER_CEILING, + ANIM_PLAYER_HACKING, + ANIM_PLAYER_ATTACH_DOWN, + ANIM_PLAYER_REACH_ROOF, + ANIM_PLAYER_ATTACH_TO_CEILING, + ANIM_PLAYER_ATTACH_FROM_CEILING, + ANIM_PLAYER_ENTER_STAIRS, + ANIM_PLAYER_EXIT_STAIRS, + ANIM_ENEMY_PATROLLING, + ANIM_ENEMY_PLAYER_STRUGGLE, + ANIM_ENEMY_KNOCK_OUT, + ANIM_ENEMY_ENTER_STAIRS, + ANIM_ENEMY_EXIT_STAIRS, + ANIM_VAULT_OPEN, + ANIM_VAULT_CLOSE, + ANIM_ALARM_ACTIVE, + ANIM_ELEVATOR_CLOSE, + ANIM_ELEVATOR_OPEN, + NUM_ANIMATIONS +}; + +class AnimationManager +{ +public: + AnimationManager(); + ~AnimationManager(); + unsigned int getNextSprite(AnimationSequence* sequence, unsigned int* index, float* timeLeft, unsigned int dT, bool* finished); + AnimationSequence* getSequence(eAnimations index); +private: + std::unique_ptr _sequences[NUM_ANIMATIONS]; +}; + +#endif \ No newline at end of file diff --git a/audio.cpp b/audio.cpp new file mode 100644 index 0000000..9f7dfbc --- /dev/null +++ b/audio.cpp @@ -0,0 +1,183 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include "audio.h" +#include "global.h" + +AudioManager::AudioManager() +{ + _device = alcOpenDevice(nullptr); + _context = alcCreateContext(_device, nullptr); + alcMakeContextCurrent(_context); + + ALCint maxmono = 0, maxstereo = 0; + alcGetIntegerv(_device, ALC_MONO_SOURCES, 1, &maxmono); + alcGetIntegerv(_device, ALC_STEREO_SOURCES, 1, &maxstereo); + + ALuint src; + for (unsigned int i = 0; i < MAX_SOURCES; i++) + { + src = 0; + alGenSources(1, &src); + LOGF((stdout, "Pushing source %i into buffer.\n", src)); + _loadedSources.push_back(src); + } + + loadWAV("./data/sounds/alarm.wav"); + loadWAV("./data/sounds/door_open.wav"); + loadWAV("./data/sounds/door_close.wav"); + loadWAV("./data/sounds/circuitbox.wav"); + loadWAV("./data/sounds/pistol.wav"); + loadWAV("./data/sounds/pistol_ready.wav"); + loadWAV("./data/sounds/menu_click.wav"); + loadWAV("./data/sounds/switch.wav"); + loadWAV("./data/sounds/link.wav"); + loadWAV("./data/sounds/jump.wav"); + loadWAV("./data/sounds/enter_crosslink.wav"); + loadWAV("./data/sounds/exit_crosslink.wav"); + loadWAV("./data/sounds/punch1.wav"); + loadWAV("./data/sounds/punch2.wav"); + loadWAV("./data/sounds/glass_break.wav"); + loadWAV("./data/sounds/elevator_arrive.wav"); + loadWAV("./data/sounds/elevator_leave.wav"); + loadWAV("./data/sounds/elevator_decelerate.wav"); +} + +AudioManager::~AudioManager() +{ + for(auto& elem : _loadedSources) + alDeleteSources(1, &elem); + + _loadedSources.clear(); + + std::map::iterator it; + + for (it = _loadedBuffers.begin(); it != _loadedBuffers.end(); it++) + { + ALuint buf = it->second; + LOGF((stdout, "Deleting OpenAL buffer %i.\n", buf)); + alDeleteBuffers(1, &buf); + } + + alcMakeContextCurrent(nullptr); + if (_context) alcDestroyContext(_context); + if (_device) alcCloseDevice(_device); +} + +void AudioManager::playSound(std::string filename) +{ + ALuint src = getNextAvailableSource(); + ALuint buf = getBuffer(filename); + + alSourcei(src, AL_BUFFER, buf); + alSource3f(src, AL_POSITION, 0, 0, 0); + alSourcePlay(src); +} + +void AudioManager::playSound3D(const char* filename, float x, float y, float z) +{ + ALuint src = getNextAvailableSource(); + ALuint buf = getBuffer(filename); + + alSourcei(src, AL_BUFFER, buf); + alSource3f(src, AL_POSITION, x, y, z); + alSourcePlay(src); +} + +void AudioManager::loadWAV(std::string filename) +{ + SDL_AudioSpec wav_spec; + Uint32 wav_length = 0; + Uint8* wav_buffer; + + if (SDL_LoadWAV(filename.c_str(), &wav_spec, &wav_buffer, &wav_length) != nullptr) + { + ALenum format; + switch(wav_spec.format) + { + case AUDIO_U8: + case AUDIO_S8: + format = wav_spec.channels == 2 ? AL_FORMAT_STEREO8 : AL_FORMAT_MONO8; + break; + case AUDIO_U16: + case AUDIO_S16: + format = wav_spec.channels == 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; + break; + default: + LOGF((stderr, "Wave file %s is of unknown format!\n", filename.c_str())); + SDL_FreeWAV(wav_buffer); + return; + break; + } + + ALuint buf; + + alGenBuffers(1, &buf); + alBufferData(buf, format, wav_buffer, wav_length, wav_spec.freq); + SDL_FreeWAV(wav_buffer); + + int slash = filename.find_last_of("/"); + int dot = filename.find_last_of("."); + + std::string bufferString = filename.substr(slash + 1, dot - slash - 1); + LOGF((stdout, "Storing %s into buffer %i.\n", bufferString.c_str(), buf)); + _loadedBuffers.insert(std::pair(bufferString, buf)); + } + else + { + LOGF((stderr, "Couldn't load wave file %s\n", filename.c_str())); + LOGF((stderr, "%s\n", SDL_GetError())); + } +} + +ALuint AudioManager::getBuffer(std::string filename) +{ + auto it = _loadedBuffers.find(filename); + if (it == _loadedBuffers.end()) + { + LOGF((stderr, "Failed to find buffer for %s\n", filename.c_str())); + return 0; + } + + return it->second; +} + +ALuint AudioManager::getNextAvailableSource() +{ + int status; + for (auto& elem : _loadedSources) + { + alGetSourcei(elem, AL_SOURCE_STATE, &status); + if (status != AL_PLAYING) + { + return elem; + } + } + + //all sounds are currently playing! + return 0; +} + +void AudioManager::setVolume(float volume) +{ + for (auto& elem : _loadedSources) + { + alSourcef(elem, AL_GAIN, volume); + } +} \ No newline at end of file diff --git a/audio.h b/audio.h new file mode 100644 index 0000000..c737357 --- /dev/null +++ b/audio.h @@ -0,0 +1,50 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#ifndef AUDIO_H +#define AUDIO_H +#include +#include +#include +#include +#include +#include +#include +#include +#define MAX_SOURCES 10 + +class AudioManager +{ +public: + AudioManager(); + ~AudioManager(); + void playSound(std::string filename); + void playSound3D(const char* filename, float x, float y, float z); + void loadWAV(std::string filename); + ALuint getBuffer(std::string filename); + ALuint getNextAvailableSource(); + void setVolume(float volume); +private: + std::map _loadedBuffers; + std::vector _loadedSources; + ALCdevice* _device; + ALCcontext* _context; +}; + +#endif diff --git a/bindings.cpp b/bindings.cpp new file mode 100644 index 0000000..d48f953 --- /dev/null +++ b/bindings.cpp @@ -0,0 +1,289 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include "bindings.h" +#include "global.h" + +BindingsManager::BindingsManager() +{ + +} + +BindingsManager::~BindingsManager() +{ +} + +eBinding BindingsManager::checkToken(std::string token) +{ + if (token == "Bind_MoveRight") return Bind_MoveRight; + if (token == "Bind_MoveLeft") return Bind_MoveLeft; + if (token == "Bind_MoveUp") return Bind_MoveUp; + if (token == "Bind_MoveDown") return Bind_MoveDown; + if (token == "Bind_ToggleCrosslink") return Bind_ToggleCrosslink; + return Bind_Nothing; +} + +std::string BindingsManager::bindingToString(eBinding binding) +{ + switch (binding) + { + case Bind_MoveRight: + return "Bind_MoveRight"; + case Bind_MoveLeft: + return "Bind_MoveLeft"; + case Bind_MoveUp: + return "Bind_MoveUp"; + case Bind_MoveDown: + return "Bind_MoveDown"; + case Bind_ToggleCrosslink: + return "Bind_ToggleCrosslink"; + default: + return ""; + } +} + +SDL_Keycode BindingsManager::getKeyFromToken(char* token) +{ + if (!strcmp(token, "A")) return SDLK_a; + if (!strcmp(token, "B")) return SDLK_b; + if (!strcmp(token, "C")) return SDLK_c; + if (!strcmp(token, "D")) return SDLK_d; + if (!strcmp(token, "E")) return SDLK_e; + if (!strcmp(token, "F")) return SDLK_f; + if (!strcmp(token, "G")) return SDLK_g; + if (!strcmp(token, "H")) return SDLK_h; + if (!strcmp(token, "I")) return SDLK_i; + if (!strcmp(token, "J")) return SDLK_j; + if (!strcmp(token, "K")) return SDLK_k; + if (!strcmp(token, "L")) return SDLK_l; + if (!strcmp(token, "M")) return SDLK_m; + if (!strcmp(token, "N")) return SDLK_n; + if (!strcmp(token, "O")) return SDLK_o; + if (!strcmp(token, "P")) return SDLK_p; + if (!strcmp(token, "Q")) return SDLK_q; + if (!strcmp(token, "R")) return SDLK_r; + if (!strcmp(token, "S")) return SDLK_s; + if (!strcmp(token, "T")) return SDLK_t; + if (!strcmp(token, "U")) return SDLK_u; + if (!strcmp(token, "V")) return SDLK_v; + if (!strcmp(token, "W")) return SDLK_w; + if (!strcmp(token, "X")) return SDLK_x; + if (!strcmp(token, "Y")) return SDLK_y; + if (!strcmp(token, "Z")) return SDLK_z; + if (!strcmp(token, "Left")) return SDLK_LEFT; + if (!strcmp(token, "Right")) return SDLK_RIGHT; + if (!strcmp(token, "Up")) return SDLK_UP; + if (!strcmp(token, "Down")) return SDLK_DOWN; + if (!strcmp(token, "RCtrl")) return SDLK_RCTRL; + if (!strcmp(token, "RAlt")) return SDLK_RALT; + if (!strcmp(token, "LCtrl")) return SDLK_LCTRL; + if (!strcmp(token, "LAlt")) return SDLK_LALT; + + return SDLK_CLEAR; +} + +std::string BindingsManager::getKeyAsString(SDL_Keycode key) +{ + switch(key) + { + case SDLK_a: + return "A"; + case SDLK_b: + return "B"; + case SDLK_c: + return "C"; + case SDLK_d: + return "D"; + case SDLK_e: + return "E"; + case SDLK_f: + return "F"; + case SDLK_g: + return "G"; + case SDLK_h: + return "H"; + case SDLK_i: + return "I"; + case SDLK_j: + return "J"; + case SDLK_k: + return "K"; + case SDLK_l: + return "L"; + case SDLK_m: + return "M"; + case SDLK_n: + return "N"; + case SDLK_o: + return "O"; + case SDLK_p: + return "P"; + case SDLK_q: + return "Q"; + case SDLK_r: + return "R"; + case SDLK_s: + return "S"; + case SDLK_t: + return "T"; + case SDLK_u: + return "U"; + case SDLK_v: + return "V"; + case SDLK_w: + return "W"; + case SDLK_x: + return "X"; + case SDLK_y: + return "Y"; + case SDLK_z: + return "Z"; + case SDLK_LEFT: + return "Left"; + case SDLK_RIGHT: + return "Right"; + case SDLK_UP: + return "Up"; + case SDLK_DOWN: + return "Down"; + case SDLK_RCTRL: + return "RCtrl"; + case SDLK_RALT: + return "RAlt"; + case SDLK_LCTRL: + return "LCtrl"; + case SDLK_LALT: + return "LAlt"; + default: + return "NONE"; + } +} + +eBinding BindingsManager::getBindingFromKey(SDL_Keycode key) +{ + auto it = _bindings.find(key); + + if (it != _bindings.end()) + { + return it->second; + } + + return Bind_Nothing; +} + +void BindingsManager::loadBindingsFromConfig(const char* filename) +{ + char* text = file_read(filename); + char* delim = (char*)" =\t\n\r"; + char* token = strtok(text, delim); + eBinding binding; + + while (token) + { + binding = checkToken(token); + token = strtok(nullptr, delim); + if (binding != Bind_Nothing) + { + SDL_Keycode key = getKeyFromToken(token); + addBinding(key, binding); + } + + if (token) + token = strtok(nullptr, delim); + } + + delete [] text; + delete [] token; + text = nullptr; + token = nullptr; + delim = nullptr; +} + +std::vector BindingsManager::getBindingsToSave() +{ + std::vector bindings; + std::string line; + std::map::iterator it; + + for (it = _bindings.begin(); it != _bindings.end(); it++) + { + line = bindingToString(it->second) + " = " + getKeyAsString(it->first) + "\n"; + bindings.push_back(line); + } + + return bindings; +} + +void BindingsManager::clearBinding(eBinding binding) +{ + std::map::iterator it; + + for (it = _bindings.begin(); it != _bindings.end(); it++) + { + if (it->second == binding) + { + _bindings.erase(it); + } + } +} + +std::string BindingsManager::getKeysBound(eBinding binding) +{ + std::string keysBound = ""; + std::map::iterator it; + + for (it = _bindings.begin(); it != _bindings.end(); it++) + { + if (it->second == binding) + { + if (keysBound != "") + { + keysBound += ";"; + } + keysBound += getKeyAsString(it->first); + } + } + if (keysBound == "") + { + keysBound = "NONE"; + } + + return keysBound; +} + +void BindingsManager::addBinding(SDL_Keycode key, eBinding binding) +{ + //erase previous keys for this binding first. + std::map::iterator it; + std::string keyAsString = getKeyAsString(key); + + if (keyAsString == "NONE") + { + return; + } + for (it = _bindings.begin(); it != _bindings.end(); it++) + { + if (it->first == key) + { + _bindings.erase(it); + } + } + + _bindings.insert(std::pair(key, binding)); +} \ No newline at end of file diff --git a/bindings.h b/bindings.h new file mode 100644 index 0000000..44de49e --- /dev/null +++ b/bindings.h @@ -0,0 +1,60 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#ifndef BINDINGS_H +#define BINDINGS_H +#include +#include +#include +#include +#include +#include +#include "file.h" +#include "global.h" + +enum eBinding +{ + Bind_Nothing = 0, + Bind_MoveLeft, + Bind_MoveRight, + Bind_MoveUp, + Bind_MoveDown, + Bind_ToggleCrosslink +}; + +class BindingsManager +{ +public: + BindingsManager(); + ~BindingsManager(); + void loadBindingsFromConfig(const char* filename); + eBinding checkToken(std::string token); + SDL_Keycode getKeyFromToken(char* token); + std::string getKeyAsString(SDL_Keycode key); + eBinding getBindingFromKey(SDL_Keycode key); + std::string bindingToString(eBinding binding); + std::vector getBindingsToSave(); + void clearBinding(eBinding binding); + std::string getKeysBound(eBinding binding); + void addBinding(SDL_Keycode key, eBinding binding); +private: + std::map _bindings; +}; + +#endif \ No newline at end of file diff --git a/button.cpp b/button.cpp new file mode 100644 index 0000000..a8d42b1 --- /dev/null +++ b/button.cpp @@ -0,0 +1,331 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include "button.h" + +TextLabel::TextLabel(int x, int y, std::string text, float r, float g, float b) +{ + _text = text; + _x = x; + _y = y; + _red = r; + _green = g; + _blue = b; + _alpha = 1.0f; + _visible = true; +} + +TextLabel::~TextLabel() +{ + +} + +std::string& TextLabel::getText() +{ + return _text; +} + +void TextLabel::getPosition(int* x, int* y) +{ + *x = _x; + *y = _y; +} + +void TextLabel::getColors(float* r, float* g, float* b, float* a) +{ + *r = _red; + *g = _green; + *b = _blue; + *a = _alpha; +} + +void TextLabel::setText(std::string text) +{ + _text = text; +} + +void TextLabel::setPosition(int x, int y) +{ + _x = x; + _y = y; +} + +void TextLabel::setPositionWithOffset(int x, int y, int xOff, int yOff) +{ + setPosition(x, y); + _x += xOff; + _y += yOff; +} + +void TextLabel::update(unsigned int dT) {} + +bool TextLabel::isVisible() +{ + return _visible; +} + +void TextLabel::setVisible(bool b) +{ + _visible = b; +} + +FloatingMessage::FloatingMessage(int x, int y, std::string text, float r, float g, float b) : TextLabel(x, y, text, r, g, b) +{ + _timeRemaining = 0; + _setTime = 0; + +} + +FloatingMessage::~FloatingMessage() +{ +} + +void FloatingMessage::update(unsigned int dT) +{ + if (_visible) + { + _timeRemaining -= dT; + + int diff = _setTime - _timeRemaining; + + if (diff < 250) + { + _alpha = ((float)(diff) / 250); + } + + if (_timeRemaining < 500) + { + _alpha = (float)(_timeRemaining) / 500; + } + if (_timeRemaining <= 0) + { + setVisible(false); + _timeRemaining = 0; + _setTime = 0; + } + } +} + +void FloatingMessage::init(int x, int y, std::string text, unsigned int timeRemaining) +{ + setPosition(x, y); + setText(text); + setTimeRemaining(timeRemaining); + _alpha = 0.0f; +} + +void FloatingMessage::setTimeRemaining(unsigned int timeRemaining) +{ + _setTime = timeRemaining; + _timeRemaining = timeRemaining; + setVisible(_timeRemaining > 0); +} + +Button::Button(int x, int y, int w, int h) +{ + _x = x; + _y = y; + _w = w; + _h = h; + + _highlighted = false; + _clickable = true; +} + +Button::Button(int x, int y, int w, int h, bool clickable) +{ + _x = x; + _y = y; + _w = w; + _h = h; + + _highlighted = false; + _clickable = clickable; +} + +Button::~Button() +{ +} + +bool Button::isMouseIntersecting(int mx, int my) +{ + return (mx >= _x && mx <= _x + _w && my >= _y && my <= _y + _h); +} + +bool Button::isHighlighted() +{ + return _highlighted; +} + +void Button::setHighlighted(bool b) +{ + _highlighted = b; +} + +int Button::getX() +{ + return _x; +} + +int Button::getY() +{ + return _y; +} + +int Button::getW() +{ + return _w; +} + +int Button::getH() +{ + return _h; +} + +void Button::setW(int w) +{ + _w = w; +} + +void Button::setPosition(int x, int y) +{ + _x = x; + _y = y; +} + +void Button::setPositionWithOffset(int x, int y, int xOff, int yOff) +{ + setPosition(x, y); + _x += xOff; + _y += yOff; +} + +bool Button::isClickable() +{ + return _clickable; +} + +//Text button functions + +TextButton::TextButton(int x, int y, int w, int h, std::string text) : Button(x, y, w, h) +{ + _text = text; + _red = 1.0f; + _green = 1.0f; + _blue = 1.0f; +} + +TextButton::TextButton(int x, int y, int w, int h, std::string text, float r, float g, float b) : Button(x, y, w, h) +{ + _text = text; + + _red = r; + _green = g; + _blue = b; +} + +TextButton::~TextButton() +{ +} + +void TextButton::changeColor(float r, float g, float b) +{ + _red = r; + _green = g; + _blue = b; +} + +const char* TextButton::getText() +{ + return _text.c_str(); +} + +void TextButton::setText(std::string text) +{ + _text = text; + _w = (text.length() + 2) * 16; +} + +void TextButton::getColors(float* r, float* g, float* b) +{ + *r = _red; + *g = _green; + *b = _blue; +} + +void TextButton::handleMouseIntersection(int mx, int my) +{ + if (isMouseIntersecting(mx, my)) + { + changeColor(0, 1, 0); + } + else + { + changeColor(1, 1, 1); + } +} + +ImageButton::ImageButton(int x, int y, int w, int h, unsigned int index) : Button(x, y, w, h) +{ + _defaultIndex = index; + _selectedIndex = index; + _currIndex = index; +} + +ImageButton::ImageButton(int x, int y, int w, int h, bool clickable, unsigned int index) : Button(x, y, w, h, clickable) +{ + _defaultIndex = index; + _selectedIndex = index; + _currIndex = index; +} + +ImageButton::ImageButton(int x, int y, int w, int h, unsigned int index, unsigned int selectedIndex) : Button(x, y, w, h) +{ + _defaultIndex = index; + _selectedIndex = selectedIndex; + _currIndex = index; +} + +ImageButton::~ImageButton() +{ + +} + +unsigned int ImageButton::getSpriteIndex() +{ + return _currIndex; +} + +void ImageButton::handleMouseIntersection(int mx, int my) +{ + if (isMouseIntersecting(mx, my)) + { + _currIndex = _selectedIndex; + } + else + { + _currIndex = _defaultIndex; + } +} + +void ImageButton::changeSprites(unsigned int index, unsigned int selectedIndex) +{ + _currIndex = _defaultIndex = index; + _selectedIndex = selectedIndex; +} \ No newline at end of file diff --git a/button.h b/button.h new file mode 100644 index 0000000..60aabc7 --- /dev/null +++ b/button.h @@ -0,0 +1,117 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#ifndef BUTTON_H +#define BUTTON_H +#include +#include + +class TextLabel +{ +public: + TextLabel(int x, int y, std::string text, float r, float g, float b); + ~TextLabel(); + std::string& getText(); + virtual void update(unsigned int dT); + bool isMouseIntersecting(int mx, int my); + void setText(std::string text); + void getPosition(int* x, int* y); + void getColors(float* r, float* g, float* b, float* a); + void setPosition(int x, int y); + void setPositionWithOffset(int x, int y, int xOff, int yOff); + bool isVisible(); + void setVisible(bool b); +protected: + std::string _text; + float _red, _green, _blue, _alpha; + int _x, _y; + bool _visible; +}; + +class FloatingMessage : public TextLabel +{ +public: + FloatingMessage(int x, int y, std::string text, float r, float g, float b); + ~FloatingMessage(); + void update(unsigned int dT); + void init(int x, int y, std::string text, unsigned int timeRemaining); + void setTimeRemaining(unsigned int timeRemaining); +private: + int _timeRemaining; + int _setTime; +}; + +class Button +{ +public: + Button(int x, int y, int w, int h); + Button(int x, int y, int w, int h, bool clickable); + virtual ~Button(); + bool isMouseIntersecting(int mx, int my); + bool isHighlighted(); + void setHighlighted(bool b); + virtual void handleMouseIntersection(int mx, int my) = 0; + int getX(); + int getY(); + int getW(); + int getH(); + void setW(int w); + void setPosition(int x, int y); + void setPositionWithOffset(int x, int y, int xOff, int yOff); + bool isClickable(); +protected: + int _x, _y; + int _w, _h; + bool _highlighted; + bool _clickable; +}; + +class TextButton : public Button +{ +public: + TextButton(int x, int y, int w, int h, std::string text); + TextButton(int x, int y, int w, int h, std::string text, float r, float g, float b); + ~TextButton(); + void changeColor(float r, float g, float b); + const char* getText(); + void setText(std::string text); + void getColors(float* r, float* g, float* b); + void handleMouseIntersection(int mx, int my); +private: + std::string _text; + float _red, _green, _blue; +}; + +class ImageButton : public Button +{ +public: + ImageButton(int x, int y, int w, int h, unsigned int index); + ImageButton(int x, int y, int w, int h, bool clickable, unsigned int index); + ImageButton(int x, int y, int w, int h, unsigned int index, unsigned int selectedIndex); + ~ImageButton(); + unsigned int getSpriteIndex(); + void handleMouseIntersection(int mx, int my); + void changeSprites(unsigned int index, unsigned int selectedIndex); +private: + unsigned int _currIndex; + unsigned int _defaultIndex; + unsigned int _selectedIndex; +}; + +#endif \ No newline at end of file diff --git a/config.cfg b/config.cfg new file mode 100644 index 0000000..9e8d9a5 --- /dev/null +++ b/config.cfg @@ -0,0 +1,16 @@ +entered_light_flash = 0 +fullscreen = 0 +screenshot_index = 0 +volume = 1 +window_x = 1280 +window_y = 720 +Bind_MoveLeft = A +Bind_MoveRight = D +Bind_MoveDown = S +Bind_MoveUp = W +Bind_MoveRight = Right +Bind_MoveLeft = Left +Bind_MoveDown = Down +Bind_MoveUp = Up +Bind_ToggleCrosslink = LAlt +Bind_ToggleCrosslink = RAlt diff --git a/config.cpp b/config.cpp new file mode 100644 index 0000000..bb7272f --- /dev/null +++ b/config.cpp @@ -0,0 +1,120 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include +#include "config.h" + +ConfigManager::ConfigManager() +{ + +} + +ConfigManager::~ConfigManager() +{ + +} + +//bindings are loaded in BindingsManager. +bool ConfigManager::isKeyValid(char* key) +{ + if (!strcmp(key, "fullscreen")) return true; + if (!strcmp(key, "window_x")) return true; + if (!strcmp(key, "window_y")) return true; + if (!strcmp(key, "screenshot_index")) return true; + if (!strcmp(key, "entered_light_flash")) return true; + if (!strcmp(key, "volume")) return true; + + return false; +} + +std::string ConfigManager::getValue(std::string key) +{ + auto it = _settings.find(key); + + return it != _settings.end() ? it->second : ""; +} + +void ConfigManager::setValue(std::string key, std::string value) +{ + if (getValue(key) != "") + { + _settings[key] = value; + } + else + { + if (isKeyValid((char*)key.c_str())) + { + _settings.insert(std::pair(key, value)); + } + } +} + +void ConfigManager::loadConfig(const char* filename) +{ + char* text = file_read(filename); + char* delim = (char*)" =\t\n\r"; + char* token = strtok(text, delim); + char* key; + + while (token) + { + key = token; + token = strtok(nullptr, delim); + + if (isKeyValid(key)) + { + _settings.insert(std::pair(std::string(key), std::string(token))); + } + + if (token) + token = strtok(nullptr, delim); + } + delete [] text; + delete [] token; + text = nullptr; + token = nullptr; + delim = nullptr; +} + +void ConfigManager::saveConfig(const char* filename, std::vector bindings) +{ + std::ofstream output(filename); + size_t i; + std::map::iterator it; + + if (!output) + { + return; + } + + for (it = _settings.begin(); it != _settings.end(); it++) + { + output << it->first << " = " << it->second << "\n"; + } + + for (i = 0; i < bindings.size(); i++) + { + output << bindings[i]; + } +} + +std::map* ConfigManager::getSettings() +{ + return &_settings; +} \ No newline at end of file diff --git a/config.h b/config.h new file mode 100644 index 0000000..ef022cd --- /dev/null +++ b/config.h @@ -0,0 +1,42 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#ifndef CONFIG_H +#define CONFIG_H +#include +#include +#include +#include +#include "file.h" + +class ConfigManager +{ +public: + ConfigManager(); + ~ConfigManager(); + void loadConfig(const char* filename); + void saveConfig(const char* filename, std::vector bindings); + bool isKeyValid(char* key); + std::string getValue(std::string key); + void setValue(std::string key, std::string value); + std::map* getSettings(); +private: + std::map _settings; +}; +#endif \ No newline at end of file diff --git a/creditsstate.cpp b/creditsstate.cpp new file mode 100644 index 0000000..5513997 --- /dev/null +++ b/creditsstate.cpp @@ -0,0 +1,74 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include "creditsstate.h" +#include "statemanager.h" + +CreditsState::CreditsState(StateManager* sm) : MenuState(sm) +{ + _cancelButton.reset(new TextButton(128, 600, (strlen("Go Back") + 2) * 16, 32, "Go Back")); + _titleLabel.reset(new TextLabel(0, 0, "Credits", 1, 1, 1)); + _credit1.reset(new TextLabel(0, 0, + "Clonepoint created by Rohit Nirmal\n\ + Gunpoint created by Tom Francis (www.pentadact.com)\n\ + \n\n\ + Libraries Used:\n\ + stb_image and stb_ttf by Sean Barrett (www.nothings.org)\n\ + TinyXML (www.grinninglizard.com/tinyxml/)\n\ + SDL2 (www.libsdl.org)\n\ + OpenAL Soft (kcat.strangesoft.net/openal.html)\n\ + \n\n\ + Special Thanks:\n\ + /agdg/ <3\ + ", 1, 1, 1)); + _buttons.push_back(_cancelButton); + _labels.push_back(_titleLabel); + _labels.push_back(_credit1); +} + +CreditsState::~CreditsState() +{ +} + +void CreditsState::resetPositions(int w, int h) +{ + _titleLabel->setPosition(w * 0.45f, h * 0.1f); + _cancelButton->setPosition(w * 0.45f, h * 0.85f); + _credit1->setPosition(w * 0.1f, h * 0.2f); +} + +void CreditsState::handleButton(Button* button) +{ + if (button == _cancelButton.get()) + { + _manager->switchToState(MAINMENU_SCREEN); + } +} + +void CreditsState::handleKeyUp(SDL_Keycode key) +{ + switch(key) + { + case SDLK_PRINTSCREEN: + _takeScreenshot(); + break; + default: + break; + } +} \ No newline at end of file diff --git a/creditsstate.h b/creditsstate.h new file mode 100644 index 0000000..4847e6b --- /dev/null +++ b/creditsstate.h @@ -0,0 +1,38 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#ifndef CREDITSTATE_H +#define CREDITSTATE_H +#include "menustate.h" + +class CreditsState : public MenuState +{ +public: + CreditsState(StateManager* sm); + ~CreditsState(); + void handleButton(Button* button); + void resetPositions(int w, int h); + void handleKeyUp(SDL_Keycode key); +private: + std::shared_ptr _cancelButton; + std::shared_ptr _titleLabel; + std::shared_ptr _credit1; +}; + +#endif \ No newline at end of file diff --git a/draw.cpp b/draw.cpp new file mode 100644 index 0000000..3bf2069 --- /dev/null +++ b/draw.cpp @@ -0,0 +1,1550 @@ +/* +Copyright 2013-2015 Rohit Nirmal + +This file is part of Clonepoint. + +Clonepoint 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 3 of the License, or +(at your option) any later version. + +Clonepoint 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 Clonepoint. If not, see . +*/ + +#include +#include "draw.h" +#include "locator.h" + +PFNGLATTACHSHADERPROC glAttachShader; +PFNGLCOMPILESHADERPROC glCompileShader; +PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObject; +PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObject; +PFNGLDELETEOBJECTARBPROC glDeleteObject; +PFNGLGETINFOLOGARBPROC glGetInfoLog; +PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameteriv; +PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocation; +PFNGLLINKPROGRAMARBPROC glLinkProgram; +PFNGLSHADERSOURCEARBPROC glShaderSource; +PFNGLUNIFORM1IARBPROC glUniform1i; +PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObject; +PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; +PFNGLBINDBUFFERPROC glBindBuffer; +PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; +PFNGLGENBUFFERSPROC glGenBuffers; +PFNGLUNIFORM3FPROC glUniform3f; +PFNGLUNIFORM2FPROC glUniform2f; +PFNGLUNIFORM1FPROC glUniform1f; +PFNGLDELETEBUFFERSPROC glDeleteBuffers; +PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; +PFNGLBUFFERDATAPROC glBufferData; +PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; +PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; +PFNGLVALIDATEPROGRAMPROC glValidateProgram; +#if _WIN32 +PFNGLACTIVETEXTUREARBPROC glActiveTexture; +#endif +PFNGLGETBUFFERSUBDATAARBPROC glGetBufferSubData; + +struct point +{ + GLfloat x; + GLfloat y; + GLfloat s; + GLfloat t; +}; + +struct SpriteVertex +{ + float position[2]; + float texcoord[2]; +}; + +Renderer::Renderer() +{ + +} + +Renderer::~Renderer() +{ + LOGF((stdout, "Running Renderer destructor.\n")); + if (pgmText) + glDeleteObject(pgmText); + if (pgmMap) + glDeleteObject(pgmMap); + if (pgmButton) + glDeleteObject(pgmButton); + if (pgmColoredSprite) + glDeleteObject(pgmColoredSprite); + if (text_vbo) + glDeleteBuffers(1, &text_vbo); + if (entRectVBO) + glDeleteBuffers(1, &entRectVBO); + if (pointVBO) + glDeleteBuffers(1, &pointVBO); + if (_screenVBO) + glDeleteBuffers(1, &_screenVBO); +} + +void Renderer::toggleWireframe() +{ + if (!wireframe) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + else + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + wireframe = !wireframe; +} + +void Renderer::init(int x, int y) +{ + _screenVBO = 0; + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + //glClearColor(0.3960784313725490196078431372549, 0.61176470588235294117647058823529, 0.93725490196078431372549019607843, 1); + + setResolution(x, y); + + pgmMap = compileShaders("shaders/main.vert", "shaders/main.frag"); + pgmText = compileShaders("shaders/text.vert", "shaders/text.frag"); + pgmButton = compileShaders("shaders/button.vert", "shaders/button.frag"); + pgmColoredSprite = compileShaders("shaders/sprite_colored.vert", "shaders/sprite_colored.frag"); + pgmLight = compileShaders("shaders/main.vert", "shaders/light.frag"); + pgmCamera = compileShaders("shaders/main.vert", "shaders/camera.frag"); + + //initialize map shader variables + + glUseProgramObject(pgmMap); + + glLinkProgram(pgmMap); /*Must link program before uniforms and after attributes?*/ + gWorldLocation = glGetUniformLocation(pgmMap, "gWorld"); + + //initialize text shader variables + /*Not sure if needed... + glUseProgram(pgmText);*/ + glBindAttribLocation(pgmText, 0, "coord"); + glBindAttribLocation(pgmText, 1, "texpos"); + uniform_color = glGetUniformLocation(pgmText, "color"); + uniform_alpha_scale = glGetUniformLocation(pgmText, "alpha_mod"); + glGenBuffers(1, &text_vbo); + + glBindAttribLocation(pgmButton, 0, "coord"); + glBindAttribLocation(pgmButton, 1, "texpos"); + + screenshotIndex = 1; + wireframe = false; + _enteredLightFlash = false; + + linkProgress = 0.0f; + + SDL_ShowCursor(SDL_DISABLE); + + bufferQuads(); + + font1.reset(new Font("./data/fonts/VeraMono.ttf", 32.0f)); + font2.reset(new Font("./data/fonts/VeraMono.ttf", 16.0f)); + + resPlayer.reset(new SpriteSheet("./data/sprites/player.png", ENTDIM, false)); + generateSheetBuffers(resPlayer.get(), ENTDIM); + + resPlayerLeft.reset(new SpriteSheet("./data/sprites/player.png", ENTDIM, true)); + generateSheetBuffers(resPlayerLeft.get(), ENTDIM); + + resGuardRight.reset(new SpriteSheet("./data/sprites/guard.png", ENTDIM, false)); + generateSheetBuffers(resGuardRight.get(), ENTDIM); + + resGuardLeft.reset(new SpriteSheet("./data/sprites/guard.png", ENTDIM, true)); + generateSheetBuffers(resGuardLeft.get(), ENTDIM); + + resEnforcerLeft.reset(new SpriteSheet("./data/sprites/enforcer.png", ENTDIM, true)); + generateSheetBuffers(resEnforcerLeft.get(), ENTDIM); + + resEnforcerRight.reset(new SpriteSheet("./data/sprites/enforcer.png", ENTDIM, false)); + generateSheetBuffers(resEnforcerRight.get(), ENTDIM); + + resProfessionalLeft.reset(new SpriteSheet("./data/sprites/professional.png", ENTDIM, true)); + generateSheetBuffers(resProfessionalLeft.get(), ENTDIM); + + resProfessionalRight.reset(new SpriteSheet("./data/sprites/professional.png", ENTDIM, false)); + generateSheetBuffers(resProfessionalRight.get(), ENTDIM); + + resSniperLeft.reset(new SpriteSheet("./data/sprites/sniper.png", ENTDIM, true)); + generateSheetBuffers(resSniperLeft.get(), ENTDIM); + + resSniperRight.reset(new SpriteSheet("./data/sprites/sniper.png", ENTDIM, false)); + generateSheetBuffers(resSniperRight.get(), ENTDIM); + + resObjects.reset(new SpriteSheet("./data/sprites/objects.png", ENTDIM, false)); + generateSheetBuffers(resObjects.get(), ENTDIM); + + resLinkables.reset(new SpriteSheet("./data/sprites/linkable.png", ENTDIM, false)); + generateSheetBuffers(resLinkables.get(), ENTDIM); + + resInterface.reset(new SpriteSheet("./data/sprites/interface.png", 32, false)); + generateSheetBuffers(resInterface.get(), 32); + + resGlass.reset(new SpriteSheet("./data/sprites/glass.png", 8, false)); + generateSheetBuffers(resGlass.get(), 8); + + mouseOverStrings[MO_Nothing] = ""; + mouseOverStrings[MO_CircuitBox] = "A circuit box. Use it to unlock its circuit."; + mouseOverStrings[MO_LightFixture] = "A light fixture. Toggles its light when activated."; + mouseOverStrings[MO_MainComputer] = "A computer terminal. Hack these to complete mission objectives."; + mouseOverStrings[MO_HandScanner] = "A hand scanner. Only guards can use these."; + mouseOverStrings[MO_Elevator] = "An elevator switch. Makes nearby enemies look when an elevator arrives."; + mouseOverStrings[MO_MotionScanner] = "A motion detector. Activates when any living entity passes through."; + mouseOverStrings[MO_Switch] = "A light switch."; + mouseOverStrings[MO_Door] = "A door. Opens or closes when activated."; + mouseOverStrings[MO_TrapDoor] = "A trap door. Opens when activated, then closes after a time."; + mouseOverStrings[MO_VaultDoor] = "A vault door. Opens when activated, then closes after a time."; + mouseOverStrings[MO_SoundDetector] = "A sound detector. Activated by loud sounds nearby."; + mouseOverStrings[MO_Alarm] = "An alarm. When activated, alerts nearby guard to turn it off."; + mouseOverStrings[MO_PowerSocket] = "A power socket. Knocks out guards nearby when activated."; + mouseOverStrings[MO_SecurityCamera] = "A security camera. Activates whenever you enter its field of vision."; + mouseOverStrings[MO_Guard] = "A Guard. Shoots on sight."; + mouseOverStrings[MO_Enforcer] = "An Enforcer. Cannot be pounced."; + mouseOverStrings[MO_Professional] = "A Professional. Has faster reflexes, can see in the dark, shoots when held at gunpoint."; + mouseOverStrings[MO_Sniper] = "A Sniper. You probably won't make it out."; + + objectivesNotCompleted = "Objectives not completed."; + + handleSettingsChange(); +} + +void Renderer::setResolution(int x, int y) +{ + winX = x; + winY = y; + orthographic = mat4f_orthographic(0.0f, winX, winY, 0.0f, -5.0f, 5.0f); + glViewport(0, 0, winX, winY); + bufferScreenVBO((float)winX, (float)winY); +} + +bool CheckGLExtension(const char* ext, const char* list) +{ + const char *str = strstr(list, ext); + if (!str) + { + return false; + } + const char ch = str[strlen(ext)]; + return ((ch == ' ') || (ch == '\t') || (ch == '\0')); +} + +bool Renderer::initShaders() +{ + char* extensions = (char*)glGetString(GL_EXTENSIONS); + + bool shaders_supported = false; + if (CheckGLExtension("GL_ARB_shader_objects", extensions) && + CheckGLExtension("GL_ARB_shading_language_100", extensions) && + CheckGLExtension("GL_ARB_vertex_shader", extensions) && + CheckGLExtension("GL_ARB_fragment_shader", extensions)) + { + glAttachShader = (PFNGLATTACHSHADERPROC)SDL_GL_GetProcAddress("glAttachShader"); + glCompileShader = (PFNGLCOMPILESHADERPROC)SDL_GL_GetProcAddress("glCompileShader"); + glCreateProgramObject = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB"); + glCreateShaderObject = (PFNGLCREATESHADEROBJECTARBPROC)SDL_GL_GetProcAddress("glCreateShaderObjectARB"); + glDeleteObject = (PFNGLDELETEOBJECTARBPROC)SDL_GL_GetProcAddress("glDeleteObjectARB"); + glGetInfoLog = (PFNGLGETINFOLOGARBPROC)SDL_GL_GetProcAddress("glGetInfoLogARB"); + glGetObjectParameteriv = (PFNGLGETOBJECTPARAMETERIVARBPROC)SDL_GL_GetProcAddress("glGetObjectParameterivARB"); + glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONARBPROC)SDL_GL_GetProcAddress("glGetUniformLocationARB"); + glLinkProgram = (PFNGLLINKPROGRAMARBPROC)SDL_GL_GetProcAddress("glLinkProgramARB"); + glShaderSource = (PFNGLSHADERSOURCEARBPROC)SDL_GL_GetProcAddress("glShaderSourceARB"); + glUniform1i = (PFNGLUNIFORM1IARBPROC)SDL_GL_GetProcAddress("glUniform1iARB"); + glUseProgramObject = (PFNGLUSEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glUseProgramObjectARB"); + glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray"); + glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glDisableVertexAttribArray"); + glBindBuffer = (PFNGLBINDBUFFERPROC)SDL_GL_GetProcAddress("glBindBuffer"); + glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)SDL_GL_GetProcAddress("glUniformMatrix4fv"); + glGenBuffers = (PFNGLGENBUFFERSPROC)SDL_GL_GetProcAddress("glGenBuffers"); + glUniform3f = (PFNGLUNIFORM3FPROC)SDL_GL_GetProcAddress("glUniform3f"); + glUniform2f = (PFNGLUNIFORM2FPROC)SDL_GL_GetProcAddress("glUniform2f"); + glUniform1f = (PFNGLUNIFORM1FPROC)SDL_GL_GetProcAddress("glUniform1f"); + glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)SDL_GL_GetProcAddress("glDeleteBuffers"); + glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)SDL_GL_GetProcAddress("glBindAttribLocation"); + glBufferData = (PFNGLBUFFERDATAPROC)SDL_GL_GetProcAddress("glBufferData"); + glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer"); + glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)SDL_GL_GetProcAddress("glGetAttribLocation"); + glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)SDL_GL_GetProcAddress("glValidateProgram"); +#if _WIN32 + glActiveTexture = (PFNGLACTIVETEXTUREARBPROC)SDL_GL_GetProcAddress("glActiveTexture"); +#endif + glGetBufferSubData = (PFNGLGETBUFFERSUBDATAARBPROC)SDL_GL_GetProcAddress("glGetBufferSubData"); + + if (glAttachShader && + glCompileShader && + glCreateProgramObject && + glCreateShaderObject && + glDeleteObject && + glGetInfoLog && + glGetObjectParameteriv && + glGetUniformLocation && + glLinkProgram && + glShaderSource && + glUniform1i && + glUseProgramObject && + glEnableVertexAttribArray && + glDisableVertexAttribArray && + glBindBuffer && + glUniformMatrix4fv && + glGenBuffers && + glUniform3f && + glUniform2f && + glUniform1f && + glDeleteBuffers && + glBindAttribLocation && + glBufferData && + glVertexAttribPointer && + glGetAttribLocation && + glValidateProgram +#if _WIN32 + && glActiveTexture +#endif + ) + { + shaders_supported = true; + } + else + { + LOGF((stderr, "Error getting OpenGL function pointers!\n")); + } + } + return shaders_supported; +} + +void Renderer::takeScreenshot() +{ + sprintf(screenshot_filename, "screenshot%i.bmp", screenshotIndex); + image = SDL_CreateRGBSurface(SDL_SWSURFACE, winX, winY, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); + glReadBuffer(GL_FRONT); + glReadPixels(0, 0, winX, winY, GL_RGB, GL_UNSIGNED_BYTE, image->pixels); + image = flipSurface(image, Flip_Vertical); + SDL_SaveBMP(image, screenshot_filename); + SDL_FreeSurface(image); + screenshotIndex++; +} + +void Renderer::drawState(std::shared_ptr state) +{ + size_t i; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (std::dynamic_pointer_cast(state)) + { + for (i = 0; i < std::static_pointer_cast(state)->getButtonCount(); i++) + { + drawButton(std::static_pointer_cast(state)->getButtonAt(i)); + } + } + else + { + drawScene(std::static_pointer_cast(state)->getScene()); + } + + for (i = 0; i < std::static_pointer_cast(state)->getLabelCount(); i++) + { + drawTextLabel(state->getLabelAt(i)); + } + drawMouseCursor(state); +} + +void Renderer::drawMouseCursor(std::shared_ptr state) +{ + int x, y; + state->getMousePosition(&x, &y); + bool safe = true; + + if (std::dynamic_pointer_cast(state) && std::static_pointer_cast(state)->isMouseCursorSeen()) + { + safe = false; + } + + drawSpriteBind(x, y, 4.0f, 0, resInterface.get(), Locator::getSpriteManager()->getIndex("./data/sprites/interface.sprites", + safe ? "pointer_safe" : "pointer_unsafe"), false, 1, 1, 1); +} + +void Renderer::drawText(float x, float y, const char* text, float red, float green, float blue, float alpha_scale, std::shared_ptr font) +{ + float xCurr = x; + glBindBuffer(GL_ARRAY_BUFFER, text_vbo); + glUseProgramObject(pgmText); + glActiveTexture(GL_TEXTURE0); + + glBindTexture(GL_TEXTURE_2D, font->getTexture()); + glUniformMatrix4fv(glGetUniformLocation(pgmText, "proj_mat"), 1, GL_TRUE, &orthographic.m[0][0]); + glUniform3f(uniform_color, red, green, blue); + glUniform1f(uniform_alpha_scale, alpha_scale); + glEnableVertexAttribArray(0); + + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr); + std::vector coords; + point p; + point top_left; + point bottom_right; + stbtt_aligned_quad q; + int c = 0; + + while (*text) + { + if ((*text >= 32 && *text < 127) || *text == '\n') + { + if (*text == '\n') + { + y += font->getSize(); + xCurr = x; + ++text; + continue; + } + stbtt_GetBakedQuad(font->data(), 512, 512, *text - 32, &xCurr, &y, &q, 1); + + p.x = q.x0; + p.y = q.y0; + p.s = q.s0; + p.t = q.t0; + coords.push_back(p); + + top_left.x = q.x0; + top_left.y = q.y1; + top_left.s = q.s0; + top_left.t = q.t1; + + bottom_right.x = q.x1; + bottom_right.y = q.y0; + bottom_right.s = q.s1; + bottom_right.t = q.t0; + + coords.push_back(top_left); + coords.push_back(bottom_right); + coords.push_back(top_left); + coords.push_back(bottom_right); + + p.x = q.x1; + p.y = q.y1; + p.s = q.s1; + p.t = q.t1; + coords.push_back(p); + + c += 6; + } + ++text; + } + + glBufferData(GL_ARRAY_BUFFER, sizeof(point) * coords.size(), coords.data(), GL_DYNAMIC_DRAW); + + glEnable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDrawArrays(GL_TRIANGLES, 0, c); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDisableVertexAttribArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void Renderer::drawTextButton(std::shared_ptr tb) +{ + float r, g, b; + + r = g = b = 0; + tb->getColors(&r, &g, &b); + drawText(tb->getX(), tb->getY() + 32, tb->getText(), r, g, b, 1.0f, font1); +} + +void Renderer::drawImageButton(std::shared_ptr ib) +{ + drawSprite(ib->getX(), ib->getY(), 2, 0, resInterface.get(), ib->getSpriteIndex(), false, 1, 1, 1); +} + +void Renderer::drawButton(std::shared_ptr