Írjunk egy rajzoló (Renderer) oszályt. Ez az osztály fogja kezelni az ablakot (SDL_Window), és a renderert (SDL_Renderer) is. Találhatók ebben az osztályban Sprite, és Texture típusú paraméterek is. Ezeket, még nem hoztuk létre, viszont ezeknek majd szüksége lessz a működésükhöz az ebben az osztályban található SDL_Renderer-re. Szóval ezeket a függvényeket csak az után rakjátok bele, miután az adott osztályokat már beimplementáltátok. ------ Ez egy ún. singleton osztály lesz. Azaz a programunkban csak egy darabot szabad létrehozni, viszont ezt utána bármikor elérhetjük a statikus get_singleton() függvényen keresztül. c++-ban ez pl így működik: Renderer::get_singleton()->present(); Fontos tudni, hogy itt nekünk kell majd egy Renderer-t létrehoznunk a programunk elején. Van olyan singleton implementáció, ami automatikusan létrejön az első elérésekor, de mivel ez az osztály pl az ablakot is kezeli, ezért itt ezt nem így fogjuk csinálni. Megj: Sok esetben érdemes a singleton-jainkat a program elején explicit létrehozatnunk, majd a végén töröltetnünk. (new, delete) Elég sok problémától kímélhetjük meg magunkat vele. (Pl.: a legtöbb játékmotoroknál ez bevett szokás.) (Nyilván ebbe az is benne van, hogy egy egy singleton allokáció kisebb megakadásokat is eredményezhet, ha annak az osztálynak sokáig tart az inícializációja.) ------ A teljesség kedvéért, c++ példa egy automatikusan létrejövő singletonra: Fontos tudni, hogy ez az implementáció thread safe az újabb c++-ban. (A fordító rak bele mutexeket! https://www.youtube.com/watch?v=c1gO9aB9nbs&t=1120s) Renderer &Renderer::get_singleton() { static Renderer r; return r; } ------ Megj.: a static Renderer *_singleton tagot így kell megcsinálni: a .h-ban: class Renderer { //... static Renderer *_singleton; } a .cpp-ben: Renderer *Renderer::_singleton = nullptr; Azaz definiálni kell, különben fordítási hibát fogtok kapni. (Itt tudunk neki kezdeti paramétert is adni.) |---------------------------------------------------------------------------------------| | class Renderer | |---------------------------------------------------------------------------------------| | + void present() | | + void set_draw_color(const Uint8 r, const Uint8 g, const Uint8 b, const Uint8 a) | | + void set_draw_color(const Color &color) | | + void clear() | | | | + SDL_BlendMode get_blend_mode | | + void set_blend_mode(const SDL_BlendMode mode) | | | | + void draw_point(const int x, const int y) | | + void draw_point(const float x, const float y) | | | | + void draw_line(const int x1, const int x2, const int y1, const int y2) | | + void draw_line(const float x1, const float x2, const float y1, const float y2) | | | | + void draw_rect(const Rect2 &rect) | | | | + void draw_fill_rect(const Rect2 &rect) | | | | + void draw_texture(const Texture &texture, const Rect2 &dst_rect) | | + void draw_texture(const Texture &texture, const Rect2 &src_rect, | | const Rect2 &dst_rect) | | | | + void draw_texture(const Texture &texture, const Rect2 &src_rect, | | const Rect2 &dst_rect, const double angle, const float cx = 0, | | const float cy = 0, const SDL_RendererFlip flip = SDL_FLIP_NONE)| | | | + void draw_sprite(const Sprite &sprite) | | + void draw_sprite(const Sprite *sprite) | | | | + int get_dpi | | + int get_window_size_w | | + int get_window_size_h | | + int get_size_w | | + int get_size_h | | + void set_size(const int w, const int h) const | | + void get_size(int *w, int *h) const | | | | + float get_scale_w | | + float get_scale_h | | + void set_scale(const float w, const float h) const | | + void get_scale(float *w, float *h) const | | | | + bool get_integer_scaling | | + void set_integer_scaling(const bool enable) | | | | + Rect2 get_viewport | | + void set_viewport(const Rect2 &rect) const | | | | + Rect2 get_clip_rect | | + void set_clip_rect(Rect2 *rect) const | | + bool clip_rect_enabled | | | | + bool render_target_supported() | | | | + SDL_Texture *get_render_target() | | + void set_render_target(Texture *texture) | | | | + void initialize() | | + void destroy() | | | | + SDL_Window *get_window() | | + SDL_Renderer *get_renderer() | | | | + Renderer() | | + Renderer(unsigned int flags, unsigned int window_flags, int window_width = 640, | | int window_height = 480) | | | | + virtual ~Renderer() | | | | + static Renderer *get_singleton() | | | | - int _initial_window_width | | - int _initial_window_height | | | | - unsigned int _flags | | - unsigned int _window_flags | | | | - SDL_Window *_window | | - SDL_Renderer *_renderer | | | | - int _window_display_index | | | | - static Renderer *_singleton | |---------------------------------------------------------------------------------------| ------------------------------------------------------------------------------------------ present: SDL_RenderPresent(_renderer) Ez fogja a végén megjeleníteni a képet. ------------------------------------------------------------------------------------------ set_draw_color: SDL_SetRenderDrawColor(_renderer, r, g, b, a) ------------------------------------------------------------------------------------------ set_draw_color: SDL_SetRenderDrawColor(_renderer, color.r, color.g, color.b, color.a) ------------------------------------------------------------------------------------------ clear: SDL_RenderClear(_renderer) ------------------------------------------------------------------------------------------ get_blend_mode: SDL_BlendMode mode SDL_GetRenderDrawBlendMode(_renderer, &mode) return mode A blend mode mondja meg, hogy az sdl hogy kezelje az átlátszó képeket. ------------------------------------------------------------------------------------------ set_blend_mode: SDL_SetRenderDrawBlendMode(_renderer, mode) ------------------------------------------------------------------------------------------ draw_point: SDL_RenderDrawPoint(_renderer, x, y) ------------------------------------------------------------------------------------------ draw_point: SDL_RenderDrawPointF(_renderer, x, y) ------------------------------------------------------------------------------------------ draw_line: SDL_RenderDrawLine(_renderer, x1, x2, y1, y2) ------------------------------------------------------------------------------------------ draw_line: SDL_RenderDrawLineF(_renderer, x1, x2, y1, y2) ------------------------------------------------------------------------------------------ draw_rect: SDL_Rect r = rect.as_rect() SDL_RenderDrawRect(_renderer, &r) ------------------------------------------------------------------------------------------ draw_fill_rect: SDL_Rect r = rect.as_rect() SDL_RenderFillRect(_renderer, &r) ------------------------------------------------------------------------------------------ draw_texture(const Texture &texture, const Rect2 &dst_rect): SDL_Rect sr sr.x = 0 sr.y = 0 sr.w = texture.get_width() sr.h = texture.get_height() SDL_Rect dr = dst_rect.as_rect() SDL_RenderCopy(_renderer, texture.get_texture(), &sr, &dr) ------------------------------------------------------------------------------------------ draw_texture(const Texture &texture, const Rect2 &src_rect, const Rect2 &dst_rect): SDL_Rect sr = src_rect.as_rect() SDL_Rect dr = dst_rect.as_rect() SDL_RenderCopy(_renderer, texture.get_texture(), &sr, &dr) ------------------------------------------------------------------------------------------ draw_texture(const Texture &texture, const Rect2 &src_rect, const Rect2 &dst_rect, const double angle, const float cx, const float cy, const SDL_RendererFlip flip): SDL_Rect sr = src_rect.as_rect() SDL_FRect dr = dst_rect.as_frect() SDL_FPoint p p.x = cx p.y = cy SDL_RenderCopyExF(_renderer, texture.get_texture(), &sr, &dr, angle, &p, flip) ------------------------------------------------------------------------------------------ draw_sprite(const Sprite &sprite): Texture *t = sprite.get_texture() if (!t): return t->set_color_mod(sprite.get_color_mod()) double angle = sprite.get_angle() if (Math::is_zero_approx(angle)): SDL_Rect sr = sprite.get_texture_clip_rect().as_rect() SDL_Rect dr = sprite.get_transform().as_rect() SDL_RenderCopy(_renderer, t->get_texture(), &sr, &dr) else: SDL_Rect sr = sprite.get_texture_clip_rect().as_rect() SDL_FRect dr = sprite.get_transform().as_frect() SDL_FPoint p p.x = sprite.get_anchor_x() p.y = sprite.get_anchor_y() SDL_RenderCopyExF(_renderer, t->get_texture(), &sr, &dr, angle, &p, sprite.get_flip()) ------------------------------------------------------------------------------------------ draw_sprite(const Sprite *sprite): if (!sprite): return Texture *t = sprite->get_texture() if (!t): return t->set_color_mod(sprite->get_color_mod()) double angle = sprite->get_angle() if (Math::is_zero_approx(angle)): SDL_Rect sr = sprite->get_texture_clip_rect().as_rect() SDL_Rect dr = sprite->get_transform().as_rect() SDL_RenderCopy(_renderer, t->get_texture(), &sr, &dr) else: SDL_Rect sr = sprite->get_texture_clip_rect().as_rect() SDL_FRect dr = sprite->get_transform().as_frect() SDL_FPoint p p.x = sprite->get_anchor_x() p.y = sprite->get_anchor_y() SDL_RenderCopyExF(_renderer, t->get_texture(), &sr, &dr, angle, &p, sprite->get_flip()) ------------------------------------------------------------------------------------------ get_dpi: float ddpi float hdpi float vdpi if (SDL_GetDisplayDPI(_window_display_index, &ddpi, &hdpi, &vdpi)): return ddpi //fallback return 1 dpi = dot per inch. Nagy pixelsőrőségű kijelzőknél lehet haszna. ------------------------------------------------------------------------------------------ get_window_size_w: int w int h SDL_GetWindowSize(_window, &w, &h) return w ------------------------------------------------------------------------------------------ get_window_size_h: int w int h SDL_GetWindowSize(_window, &w, &h) return h ------------------------------------------------------------------------------------------ get_size_w: int w int h SDL_RenderGetLogicalSize(_renderer, &w, &h) return w ------------------------------------------------------------------------------------------ get_size_h: int w int h SDL_RenderGetLogicalSize(_renderer, &w, &h) return h ------------------------------------------------------------------------------------------ get_size: SDL_RenderGetLogicalSize(_renderer, w, h) ------------------------------------------------------------------------------------------ set_size: SDL_RenderSetLogicalSize(_renderer, w, h) ------------------------------------------------------------------------------------------ get_scale_w: float w float h SDL_RenderGetScale(_renderer, &w, &h) return w ------------------------------------------------------------------------------------------ get_scale_h: float w float h SDL_RenderGetScale(_renderer, &w, &h) return h ------------------------------------------------------------------------------------------ set_scale: SDL_RenderSetScale(_renderer, w, h) ------------------------------------------------------------------------------------------ get_scale: SDL_RenderGetScale(_renderer, w, h) ------------------------------------------------------------------------------------------ get_integer_scaling: return SDL_RenderGetIntegerScale(_renderer) ------------------------------------------------------------------------------------------ set_integer_scaling: if (enable): SDL_RenderSetIntegerScale(_renderer, SDL_TRUE) else: SDL_RenderSetIntegerScale(_renderer, SDL_FALSE) ------------------------------------------------------------------------------------------ get_viewport: SDL_Rect r SDL_RenderGetViewport(_renderer, &r) return Rect2(r.x, r.y, r.w, r.h) ------------------------------------------------------------------------------------------ set_viewport: SDL_Rect r = rect.as_rect() SDL_RenderSetViewport(_renderer, &r) ------------------------------------------------------------------------------------------ get_clip_rect: SDL_Rect r SDL_RenderGetClipRect(_renderer, &r) return Rect2(r.x, r.y, r.w, r.h) A beállított clip rect-en belüli pixelek fognak az ablakban megjelenni. Alapból 0, 0, get_screen_width(), get_screen_heigth(). A kamera ezt fogja állítgatni. ------------------------------------------------------------------------------------------ set_clip_rect: if (rect): SDL_Rect r = rect->as_rect() SDL_RenderSetClipRect(_renderer, &r) else: SDL_RenderSetClipRect(_renderer, nullptr) ------------------------------------------------------------------------------------------ clip_rect_enabled: return SDL_RenderIsClipEnabled(_renderer) ------------------------------------------------------------------------------------------ render_target_supported: return SDL_RenderTargetSupported(_renderer) ------------------------------------------------------------------------------------------ get_render_target: return SDL_GetRenderTarget(_renderer) ------------------------------------------------------------------------------------------ set_render_target: if (texture): SDL_SetRenderTarget(_renderer, texture->get_texture()) else: SDL_SetRenderTarget(_renderer, nullptr) Így lehet textúrára rajzolni. ------------------------------------------------------------------------------------------ initialize: if (SDL_Init(_flags) != 0): printf("SDL_Init() hiba!\n") return if (SDL_CreateWindowAndRenderer(_initial_window_width, _initial_window_height, _window_flags, &_window, &_renderer) != 0): printf("SDL_CreateWindowAndRenderer() hiba!\n") return _window_display_index = SDL_GetWindowDisplayIndex(_window) ------------------------------------------------------------------------------------------ destroy: if (_window): SDL_DestroyWindow(_window) if (_renderer): SDL_DestroyRenderer(_renderer) _window = nullptr _renderer = nullptr ------------------------------------------------------------------------------------------ get_window: return _window ------------------------------------------------------------------------------------------ get_renderer: return _renderer ------------------------------------------------------------------------------------------ Renderer(): if (_singleton): printf("Renderer(): _singleton is not null!\n") _initial_window_width = 640 _initial_window_height = 480 _singleton = this _flags = SDL_INIT_VIDEO | SDL_INIT_TIMER _window_flags = SDL_WINDOW_SHOWN initialize() ------------------------------------------------------------------------------------------ Renderer(unsigned int flags, unsigned int window_flags, int initial_window_width, int initial_window_height): if (_singleton): printf("Renderer(flags): _singleton is not null!\n") _initial_window_width = initial_window_width _initial_window_height = initial_window_height _singleton = this _flags = flags _window_flags = window_flags initialize() ------------------------------------------------------------------------------------------ ~Renderer: if (_singleton != this): printf("~Renderer(): _singleton is not this!\n") _singleton = nullptr destroy() ------------------------------------------------------------------------------------------ get_singleton: return _singleton ------------------------------------------------------------------------------------------