diff --git a/Makefile b/Makefile index b2992bcd27b4b8d4665b1604502a5317cf460693..213bfcda2957ccce7b0a6512fded9141edc9ff06 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ $(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) $(ECHO) compiling $< clang -c $(CFLAGS) $< -o $@ -all: $(BUILD_DIR)/splat $(BUILD_DIR)/shapes +all: $(BUILD_DIR)/splat $(BUILD_DIR)/shapes $(BUILD_DIR)/sprite $(BUILD_DIR)/splat: $(OBJECTS) $(BUILD_DIR)/splat.o Makefile $(ECHO) linking $< @@ -45,6 +45,12 @@ $(BUILD_DIR)/shapes: $(OBJECTS) $(BUILD_DIR)/shapes.o Makefile # $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(BUILD_DIR)/splat.o $(ECHO) success +$(BUILD_DIR)/sprite: $(OBJECTS) $(BUILD_DIR)/sprite.o Makefile + $(ECHO) linking $< + $(CC) -L./osx/lib/ -lSDL2 -lSDL2_ttf -lSDL2_image -lfreetype -lpng -lwebp -ltiff -ljpeg -lbz2 -lz -framework OpenGL -o $@ $(OBJECTS) build/sprite.o + # $(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(BUILD_DIR)/splat.o + $(ECHO) success + ####################################### # clean up ####################################### diff --git a/examples/shapes.cpp b/examples/shapes.cpp index f1054d5d333848e8a0627a9d954cf634ff66395a..0d6ce8bf88efc2621ba702343ab365d61af46f51 100644 --- a/examples/shapes.cpp +++ b/examples/shapes.cpp @@ -3,8 +3,6 @@ #include <vector> #include <cstring> -#include <SDL2/SDL.h> - #include <context.hpp> #include <app.hpp> @@ -23,7 +21,7 @@ private: uwe::Font font15_; public: - MyApp(int width, int height); + MyApp(int width, int height, std::string title); ~MyApp(); void begin() override; @@ -35,10 +33,10 @@ public: uwe::Image render_text(std::string msg); }; -MyApp::MyApp(int width, int height): +MyApp::MyApp(int width, int height, std::string title): width_{width}, height_{height} { - init(width, height); + init(width, height, title); } MyApp::~MyApp() { @@ -138,22 +136,10 @@ uwe::Image MyApp::render_text(std::string msg) { return image; } -// int WINAPI WinMain( -// HINSTANCE hInstance, -// HINSTANCE hPrevInstance, -// PWSTR lpCmdLine, -// int nCmdShow) { -// SDL_SetMainReady(); -// std::cout << "here" << std::endl; - -// return 0; -// } - -//int main( int argc, char** argv ) { int main(int argc, char *argv[]) { //SDL_SetMainReady(); - uwe::App* app = new MyApp{width, height}; + uwe::App* app = new MyApp{width, height, "Shapes Example"}; std::cout << "here 2" << std::endl; //app->dump_renderer_info(); diff --git a/examples/splat.cpp b/examples/splat.cpp index 8add178b3e54f2937746a16afdd6ecff37d8be39..d6a9ce1a9b5e1e41c6731976596af56b8b91b5f9 100644 --- a/examples/splat.cpp +++ b/examples/splat.cpp @@ -14,7 +14,7 @@ private: int width_; int height_; public: - MyApp(int width, int height); + MyApp(int width, int height, std::string); ~MyApp(); void begin() override; @@ -24,10 +24,10 @@ public: void key_pressed(uwe::Scancode scancode, bool repeat) override; }; -MyApp::MyApp(int width, int height): +MyApp::MyApp(int width, int height, std::string title): width_{width}, height_{height} { - init(width, height); + init(width, height, title); } MyApp::~MyApp() { @@ -57,7 +57,7 @@ void MyApp::draw() { const unsigned int offset = ( get_framebuffer_width() * 4 * y ) + x * 4; - set_framebuffer( + set_framebuffer_non_scaled( offset, uwe::Colour{ static_cast<uint8_t>(rand() % 256), @@ -71,7 +71,7 @@ void MyApp::draw() { int main( int argc, char** argv ) { - uwe::App* app = new MyApp{width, height}; + uwe::App* app = new MyApp{width, height, "Splat Example"}; //app->dump_renderer_info(); app->run(); diff --git a/examples/sprite.cpp b/examples/sprite.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b074fe72ec6b85c8f4b06616a5c47a01c3de2784 --- /dev/null +++ b/examples/sprite.cpp @@ -0,0 +1,270 @@ +#include <iostream> +#include <iomanip> +#include <vector> +#include <cstring> +#include <tuple> + +#include <context.hpp> +#include <app.hpp> + +using namespace std; + +const int width = 640; +const int height = 480; + +const int COLOUR_INDEX_X = 30; +const int COLOUR_INDEX_Y = 420; + +const int COLOUR_PALATE_WIDTH = 20; +const int COLOUR_PALATE_HEIGHT = 20; + +const int COLOUR_CURRENT_X = 30; +const int COLOUR_CURRENT_Y = 30; + +const int SPRITE_WIDTH = 16; +const int SPRITE_HEIGHT = 16; + +const int SPRITE_DISPLAY_X = 500; +const int SPRITE_DISPLAY_Y = 220; + +const int SPRITE_EDITOR_X = 250; +const int SPRITE_EDITOR_Y = 150; + +const int SPRITE_EDITOR_PIXELS_WIDTH = 8; +const int SPRITE_EDITOR_PIXELS_HEIGHT = 8; + +const int SPRITE_EDITOR_CELL_TIMES = 8; + +const int SPRITE_START_X = 100; +const int SPRITE_START_Y = 100; + +class MyApp: public uwe::App { +private: + int width_; + int height_; + + int colour_index_x_; + int colour_index_y_; + int colour_index_overall_width_; + vector<uwe::Colour> colour_palate_; + + uwe::Colour current_colour_; + + vector<uwe::Colour> sprite_; + + int sprite_x_; + int sprite_y_; + + bool mouse_down_; + + bool editor_active_; +public: + MyApp(int width, int height, std::string title); + ~MyApp(); + + size_t number_colours() const { + return colour_palate_.size(); + } + + bool hit_palate(int x, int y, size_t& hit_index) { + if (x >= colour_index_x_ && x <= colour_index_overall_width_ * number_colours() && + y >= colour_index_y_ && y <= colour_index_y_ + COLOUR_PALATE_HEIGHT) { + hit_index = (x - colour_index_x_) / COLOUR_PALATE_WIDTH; + return true; + } + + return false; + } + + bool hit_editor(int x, int y, size_t& hit_index) { + if (x >= SPRITE_EDITOR_X && x <= SPRITE_EDITOR_X + SPRITE_EDITOR_PIXELS_WIDTH*SPRITE_WIDTH && + y >= SPRITE_EDITOR_Y && y <= SPRITE_EDITOR_Y + SPRITE_EDITOR_PIXELS_HEIGHT*SPRITE_HEIGHT ) { + hit_index = (x - SPRITE_EDITOR_X) / (SPRITE_EDITOR_PIXELS_WIDTH); + int tmp = (y - SPRITE_EDITOR_Y) / SPRITE_EDITOR_PIXELS_HEIGHT; + hit_index = hit_index + SPRITE_WIDTH*tmp; + return true; + } + return false; + } + + void begin() override; + void update() override; + void draw() override; + + void key_pressed(uwe::Scancode scancode, bool repeat) override; + + void mouse_pressed(int x, int y, uwe::Button button) override; + void mouse_released(int x, int y, uwe::Button button) override; + void mouse_moved(int x, int y) override; +}; + +MyApp::MyApp(int width, int height, std::string title): + width_{width}, + height_{height}, + colour_index_x_{COLOUR_INDEX_X}, + colour_index_y_{COLOUR_INDEX_Y}, + current_colour_{uwe::Colour::black()}, + sprite_(SPRITE_WIDTH*SPRITE_HEIGHT, uwe::Colour::white()), + mouse_down_{false}, + editor_active_{false}, + sprite_x_{SPRITE_START_X}, + sprite_y_{SPRITE_START_Y} { + init(width, height, title); + + colour_palate_.push_back(uwe::Colour::white()); + colour_palate_.push_back(uwe::Colour::green()); + colour_palate_.push_back(uwe::Colour::blue()); + colour_palate_.push_back(uwe::Colour::red()); + + colour_index_overall_width_ = COLOUR_PALATE_WIDTH * number_colours(); + + current_colour_ = colour_palate_[0]; +} + +MyApp::~MyApp() { + +} + +void MyApp::begin() { + +} + +void MyApp::update() { + +} + +void MyApp::key_pressed(uwe::Scancode scancode, bool repeat) { + switch (scancode) { + // enable framerate dump + case uwe::Scancode::L: { + toggle_framerate(); + break; + } + // switch to editor + case uwe::Scancode::D_1: { + editor_active_ = false; + break; + } + // switch to scene + case uwe::Scancode::D_2: { + editor_active_ = true; + break; + } + case uwe::Scancode::LEFT: { + if (!editor_active_) { + sprite_x_ = sprite_x_ - 2; + } + break; + // TODO: bounds check against window + } + case uwe::Scancode::RIGHT: { + if (!editor_active_) { + sprite_x_ = sprite_x_ + 2; + } + break; + } + case uwe::Scancode::UP: { + if (!editor_active_) { + sprite_y_ = sprite_y_ - 4; + } + break; + } + case uwe::Scancode::DOWN: { + if (!editor_active_) { + sprite_y_ = sprite_y_ + 2; + } + break; + } + default: { + // nothing see here + } + } +} + +void MyApp::mouse_pressed(int x, int y, uwe::Button button) { + if (editor_active_) { + size_t hit_index; + if (hit_palate(x, y, hit_index)) { + current_colour_ = colour_palate_[hit_index]; + } + else if (hit_editor(x, y, hit_index)) { + sprite_[hit_index] = current_colour_; + } + } + + mouse_down_ = true; +} + +void MyApp::mouse_released(int x, int y, uwe::Button button) { + mouse_down_ = false; +} + +void MyApp::mouse_moved(int x, int y) { + size_t hit_index; + if (mouse_down_ && hit_editor(x, y, hit_index)) { + sprite_[hit_index] = current_colour_; + } +} + +void MyApp::draw() { + clear(uwe::Colour::black()); + + // Below we demostrate the use of both the framebuffer and drawing primitives. + clear_framebuffer(uwe::Colour::black()); + + if (editor_active_) { + // draw sprite as actually seen + int i = 0; + for (int y = 0; y < SPRITE_HEIGHT; y++) { + for (int x = 0; x < SPRITE_WIDTH; x++) { + // draw sprite as actually seen + set_framebuffer(x + SPRITE_DISPLAY_X, y + SPRITE_DISPLAY_Y, sprite_[i]); + + // draw sprite editor + for (int y_times = 0; y_times < SPRITE_EDITOR_PIXELS_HEIGHT; y_times++) { + for (int x_times = 0; x_times < SPRITE_EDITOR_PIXELS_WIDTH; x_times++) { + set_framebuffer( + x*SPRITE_EDITOR_PIXELS_WIDTH + SPRITE_EDITOR_X + x_times, + y*SPRITE_EDITOR_PIXELS_HEIGHT + SPRITE_EDITOR_Y + y_times, + sprite_[i]); + } + } + i++; + } + } + + blit_framebuffer(); + + // draw colour palate + for (int i = 0; i < number_colours(); i++) { + set_draw_color(colour_palate_[i]); + draw_rect_fill( + colour_index_x_ + i*COLOUR_PALATE_WIDTH, colour_index_y_, COLOUR_PALATE_WIDTH, COLOUR_PALATE_HEIGHT); + } + + // draw current colour + set_draw_color(current_colour_); + draw_rect_fill(COLOUR_CURRENT_X, COLOUR_CURRENT_Y, COLOUR_PALATE_WIDTH, COLOUR_PALATE_HEIGHT); + } + else { + // draw scene + int i = 0; + for (int y = 0; y < SPRITE_HEIGHT; y++) { + for (int x = 0; x < SPRITE_WIDTH; x++) { + // draw sprite as actually seen + set_framebuffer(x + sprite_x_, y + sprite_y_, sprite_[i]); + i++; + } + } + blit_framebuffer(); + } +} + +int main(int argc, char *argv[]) { + uwe::App* app = new MyApp{width, height, "Sprite Example"}; + std::cout << "here 2" << std::endl; + + app->run(); + + return 0; +} \ No newline at end of file diff --git a/include/app.hpp b/include/app.hpp index 90e1b2029fef62e201d48dbe431b05247ae1ed8b..3d13b91bc0bb745578f109484fc0cee6e4fdbdd0 100644 --- a/include/app.hpp +++ b/include/app.hpp @@ -18,7 +18,7 @@ namespace uwe { App(); ~App(); - void init(int width, int height); + void init(int width, int height, std::string title); void run(); /// toggles output framerate to console @@ -38,15 +38,15 @@ namespace uwe { }; - virtual void mouse_pressed() { + virtual void mouse_pressed(int x, int y, Button button) { }; - virtual void mouse_released() { + virtual void mouse_released(int x, int y, Button button) { }; - virtual void mouse_moved() { + virtual void mouse_moved(int x, int y) { }; @@ -64,10 +64,21 @@ namespace uwe { return context_.pixel(offset); } - void set_framebuffer(size_t offset, Colour colour) { + void set_framebuffer_non_scaled(size_t offset, Colour colour) { context_.set_pixel(offset, colour); } + void set_framebuffer(int x, int y, Colour colour) { + int offset = x*sizeof(uwe::Colour) + get_framebuffer_width() * sizeof(uwe::Colour) * y; + context_.set_pixel(offset, colour); + } + + void clear_framebuffer(Colour colour) { + for (int offset = 0; offset < get_framebuffer_width() * get_framebuffer_height() * 4; offset++) { + context_.set_pixel(offset, colour); + } + } + void blit_framebuffer() { // copy framebuffer pixels to GPU texture for rendering SDL_UpdateTexture( diff --git a/include/context.hpp b/include/context.hpp index 47856456551d349784dc5e569ca56eeb0e07b4cd..b48cb91255620d4d0b3ccdb2faea3c6f1607c2f8 100644 --- a/include/context.hpp +++ b/include/context.hpp @@ -27,6 +27,12 @@ namespace uwe { alpha_{alpha} { } + Colour(const Colour& colour) : + red_{colour.red_}, + green_{colour.green_}, + blue_{colour.blue_}, + alpha_{colour.alpha_} { } + static Colour red() { return Colour{ 255, 0, 0, SDL_ALPHA_OPAQUE }; } @@ -78,7 +84,7 @@ namespace uwe { /// Destory context ~Context(); - void init(int width, int height); + void init(int width, int height, std::string title); /// Output details of GPU backend and texture formats void dump_renderer_info(); @@ -115,9 +121,9 @@ namespace uwe { } void set_pixel(size_t offset, Colour colour) { - pixels_[offset + 0] = colour.red_; + pixels_[offset + 0] = colour.blue_; pixels_[offset + 1] = colour.green_; - pixels_[offset + 2] = colour.blue_; + pixels_[offset + 2] = colour.red_; pixels_[offset + 3] = colour.alpha_; } diff --git a/include/events.hpp b/include/events.hpp index 328beebfe51a4c0edee35a0b030c6e23d42fd77d..398b8fb08e40f0dd44e047ffb91f4deadf3b73ef 100644 --- a/include/events.hpp +++ b/include/events.hpp @@ -68,4 +68,9 @@ namespace uwe { RIGHT = SDL_SCANCODE_RIGHT, }; + enum class Button { + LEFT = SDL_BUTTON_LEFT, + RIGHT = SDL_BUTTON_RIGHT, + }; + } // namespace uwe \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index a4dddc903751c29eac72ac94dc4065f45e0d1712..98f8ac9556ac2c485f2f7651745200b18cb78051 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -19,8 +19,8 @@ namespace uwe { } - void App::init(int width, int height) { - context_.init(width, height); + void App::init(int width, int height, std::string title) { + context_.init(width, height, title); } void App::run() { @@ -34,17 +34,34 @@ namespace uwe { while( running ) { - while( SDL_PollEvent( &event ) ) { - if( ( SDL_QUIT == event.type ) || - ( SDL_KEYDOWN == event.type && SDL_SCANCODE_ESCAPE == event.key.keysym.scancode ) ) { + while( SDL_PollEvent( &event ) && running ) { + if (event.type == SDL_QUIT || + (SDL_KEYDOWN == event.type && SDL_SCANCODE_ESCAPE == event.key.keysym.scancode) ) { running = false; break; } - else if (event.type == SDL_KEYDOWN) { - key_pressed(static_cast<Scancode>(event.key.keysym.scancode), event.key.repeat != 0); - } - else if (event.type == SDL_KEYUP) { - key_released(static_cast<Scancode>(event.key.keysym.scancode)); + + switch (event.type) { + case SDL_KEYDOWN: { + key_pressed(static_cast<Scancode>(event.key.keysym.scancode), event.key.repeat != 0); + break; + } + case SDL_KEYUP: { + key_released(static_cast<Scancode>(event.key.keysym.scancode)); + break; + } + case SDL_MOUSEBUTTONDOWN: { + mouse_pressed(event.button.x, event.button.y, static_cast<Button>(event.button.button)); + break; + } + case SDL_MOUSEBUTTONUP: { + mouse_released(event.button.x, event.button.y, static_cast<Button>(event.button.button)); + break; + } + case SDL_MOUSEMOTION: { + mouse_moved(event.motion.x, event.motion.y); + break; + } } } diff --git a/src/context.cpp b/src/context.cpp index 10db6da8c7288d8170260181e4dc8a8fd6c77ccc..4fb269e44ac0a8c39853412fd04b4821eba95191 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -8,7 +8,7 @@ namespace uwe { Context::Context() { } - void Context::init(int width, int height) { + void Context::init(int width, int height, std::string title) { width_ = width; height_ = height; tex_width_ = width; @@ -22,6 +22,8 @@ namespace uwe { width_, height_, SDL_WINDOW_SHOWN); + SDL_SetWindowTitle(window_, title.c_str()); + renderer_ = SDL_CreateRenderer( window_, -1,