add render

This commit is contained in:
方而静 2023-05-30 21:03:04 +08:00
parent f325ea6290
commit bc4c5b6ec4
12 changed files with 446 additions and 12 deletions

BIN
assets/basic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -5,19 +5,25 @@
#include <complex>
#include <initializer_list>
namespace arras {
using Float = float;
using Vec2 = std::complex<Float>;
const Float eps = 1e-6;
Float cross(const Vec2& a, const Vec2& b) {
inline Float cross(const Vec2& a, const Vec2& b) {
return a.real() * b.imag() - a.imag() * b.real();
}
Float dot(const Vec2& a, const Vec2& b) {
inline Float dot(const Vec2& a, const Vec2& b) {
return a.real() * b.real() + a.imag() * b.imag();
}
inline Float asAngle(const Vec2& d) {
return std::atan2(d.imag(), d.real());
}
struct Circle {
Vec2 o;
Float r;
@ -39,8 +45,10 @@ struct Polygon {
Polygon(const std::array<Vec2, n>& v): vertex(v) {}
Polygon(std::initializer_list<Vec2>&& v) {
int i = 0;
for (auto &&x : v) {
if (i >= n) break;
for (auto&& x : v) {
if (i >= n) {
break;
}
vertex[i] = x;
i += 1;
}
@ -64,12 +72,12 @@ struct Polygon {
}
};
bool intersect(const Circle& a, const Circle& b) {
inline bool intersect(const Circle& a, const Circle& b) {
return abs(a.o - b.o) <= a.r + b.r;
}
template<int n, int m>
bool intersect(const Polygon<n>& a, const Polygon<m>& b) {
inline bool intersect(const Polygon<n>& a, const Polygon<m>& b) {
for (int i = 0; i < n; i++) {
if (b.contain(a[i])) {
return true;
@ -98,7 +106,7 @@ bool intersect(const Polygon<n>& a, const Polygon<m>& b) {
}
template<int n>
bool intersect(const Polygon<n>& a, const Circle& b) {
inline bool intersect(const Polygon<n>& a, const Circle& b) {
if (a.contain(b.o)) {
return true;
}
@ -121,8 +129,9 @@ bool intersect(const Polygon<n>& a, const Circle& b) {
}
template<int n>
bool intersect(const Circle& b, const Polygon<n>& a) {
inline bool intersect(const Circle& b, const Polygon<n>& a) {
return intersect(a, b);
}
}
#endif

98
include/render.h Normal file
View File

@ -0,0 +1,98 @@
#ifndef HEADER_ARRAS_RENDER_H
#define HEADER_ARRAS_RENDER_H
extern "C" {
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
}
#include "2d.h"
#include <fmt/core.h>
#include <memory>
#include <stdexcept>
#include <utility>
namespace arras {
struct Color {
uint8_t r, g, b, a;
Color();
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
};
std::shared_ptr<SDL_Rect> makeRect(int x, int y, int w, int h);
std::shared_ptr<SDL_FRect> makeFRect(const arras::Vec2& pos, const arras::Vec2& size);
class RenderSurface {
public:
RenderSurface(RenderSurface&& rs);
RenderSurface(const RenderSurface& rs);
explicit RenderSurface(SDL_RWops* src);
RenderSurface(int width, int height);
~RenderSurface();
SDL_Surface* nativeHandle() const noexcept;
int width() const noexcept;
int height() const noexcept;
private:
SDL_Surface* s;
};
class RenderWindow;
class RenderTexture {
RenderTexture(const RenderTexture&) = delete;
RenderTexture& operator=(const RenderTexture&) = delete;
public:
RenderTexture(RenderTexture&& rt);
RenderTexture(const RenderWindow& rd, SDL_RWops* src);
RenderTexture(const RenderWindow& rd, const RenderSurface& rs);
~RenderTexture();
SDL_Texture* nativeHandle() const noexcept;
int width() const noexcept;
int height() const noexcept;
std::pair<int, int> calcRenderSize(int w, int h) const noexcept;
private:
SDL_Texture* t;
int w, h;
};
class RenderWindow {
RenderWindow(const RenderWindow&) = delete;
RenderWindow& operator=(const RenderWindow&) = delete;
public:
RenderWindow(RenderWindow&& rd);
RenderWindow(int w, int h);
~RenderWindow();
SDL_Renderer* nativeHandle() const noexcept;
void renderTextureAt(const RenderTexture& t, const Vec2& pos) const;
void renderTextureAt(const RenderTexture& t, const Vec2& pos, const Vec2& direction) const;
void present() const noexcept;
void clear(const Color& c = {}) const;
int width() const noexcept;
int height() const noexcept;
private:
int w, h;
SDL_Window* window;
SDL_Renderer* renderer;
};
} // namespace arras
#endif

32
main.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "2d.h"
#include "render.h"
#include <chrono>
#include <thread>
#include <cmath>
int main() {
arras::RenderWindow w(2360, 1240);
arras::RenderTexture t(w, SDL_RWFromFile("assets/basic.png", "rb"));
std::printf("%d %d\n", t.width(), t.height());
const float PI = acos(-1);
arras::Vec2 d{1, 0}, v{std::cos(PI / 300), std::sin(PI / 300)};
SDL_Event evt;
while (true) {
while (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) {
break;
}
}
w.clear();
w.renderTextureAt(t, {200, 200}, d);
w.present();
d *= v;
// pos += v;
// if (pos.real() > 1000 || pos.real() < 200) {
// v *= -1;
// }
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
}

32
objects.hpp Normal file
View File

@ -0,0 +1,32 @@
#ifndef HEADER_OBJECTS_HPP
#define HEADER_OBJECTS_HPP
#include "2d.h"
#include <entt/entt.hpp>
namespace arras {
struct Transform {
Vec2 position;
};
struct Velocity {
Vec2 velocity;
};
struct EngineAcceleration {
Vec2 ideal_velocity;
Float acceleration;
};
inline entt::entity makeTank(entt::registry &r, Vec2 position) {
const auto e = r.create();
r.emplace<Transform>(e, Transform{position});
r.emplace<Velocity>(e, Velocity{{0, 0}});
r.emplace<EngineAcceleration>(e, EngineAcceleration{{0, 0}, 1});
return e;
}
}
#endif

42
src/render/misc.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "render.h"
namespace {
class SDLLoader {
private:
SDLLoader() {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best");
IMG_Init(IMG_INIT_PNG);
}
~SDLLoader() {
IMG_Quit();
SDL_Quit();
}
static const SDLLoader _;
};
} // namespace
arras::Color::Color(): r(255), g(255), b(255), a(255) {}
arras::Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a): r(r), g(g), b(b), a(a) {}
std::shared_ptr<SDL_Rect> arras::makeRect(int x, int y, int w, int h) {
auto res = std::make_shared<SDL_Rect>();
res->x = x;
res->y = y;
res->w = w;
res->h = h;
return res;
}
std::shared_ptr<SDL_FRect> arras::makeFRect(const arras::Vec2& pos, const arras::Vec2& size) {
auto res = std::make_shared<SDL_FRect>();
res->x = pos.real();
res->y = pos.imag();
res->w = size.real();
res->h = size.imag();
return res;
}

53
src/render/surface.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "render.h"
using namespace arras;
RenderSurface::RenderSurface(RenderSurface&& rs): s(rs.s) {
rs.s = nullptr;
}
RenderSurface::RenderSurface(const RenderSurface& rs) {
s = SDL_CreateRGBSurfaceWithFormat(0, rs.width(), rs.height(), 32, SDL_PIXELFORMAT_RGBA8888);
if (!s) {
throw std::runtime_error(
fmt::format("SDL_CreateRGBSurfaceWithFormat() failed: {}", SDL_GetError()));
}
if (SDL_BlitSurface(rs.nativeHandle(),
nullptr,
s,
makeRect(0, 0, rs.width(), rs.height()).get())
!= 0) {
throw std::runtime_error(fmt::format("SDL_BlitSurface() failed: {}", SDL_GetError()));
}
}
RenderSurface::RenderSurface(SDL_RWops* src) {
s = IMG_Load_RW(src, 1);
if (!s) {
throw std::runtime_error(fmt::format("IMG_Load_RW() failed: {}", IMG_GetError()));
}
}
RenderSurface::RenderSurface(int width, int height) {
s = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA8888);
if (!s) {
throw std::runtime_error(
fmt::format("SDL_CreateRGBSurfaceWithFormat() failed: {}", SDL_GetError()));
}
}
RenderSurface ::~RenderSurface() {
SDL_FreeSurface(s);
}
SDL_Surface* RenderSurface::nativeHandle() const noexcept {
return s;
}
int RenderSurface::width() const noexcept {
return s->w;
}
int RenderSurface::height() const noexcept {
return s->h;
}

63
src/render/texture.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "render.h"
using namespace arras;
RenderTexture::RenderTexture(RenderTexture&& rt): t(rt.t) {
rt.t = nullptr;
}
RenderTexture::RenderTexture(const RenderWindow& rd, SDL_RWops* src) {
t = IMG_LoadTexture_RW(rd.nativeHandle(), src, 1);
if (!t) {
throw std::runtime_error(fmt::format("IMG_LoadTexture_RW() failed: {}", IMG_GetError()));
}
if (SDL_QueryTexture(t, nullptr, nullptr, &w, &h) != 0) {
throw std::runtime_error(fmt::format("SDL_QueryTexture() failed: {}", SDL_GetError()));
}
}
RenderTexture::RenderTexture(const RenderWindow& rd, const RenderSurface& rs) {
t = SDL_CreateTextureFromSurface(rd.nativeHandle(), rs.nativeHandle());
if (!t) {
throw std::runtime_error(
fmt::format("SDL_CreateRGBSurfaceWithFormat() failed: {}", SDL_GetError()));
}
if (SDL_QueryTexture(t, nullptr, nullptr, &w, &h)) {
throw std::runtime_error(fmt::format("SDL_QueryTexture() failed: {}", SDL_GetError()));
}
}
RenderTexture::~RenderTexture() {
SDL_DestroyTexture(t);
}
SDL_Texture* RenderTexture::nativeHandle() const noexcept {
return t;
}
int RenderTexture::width() const noexcept {
return w;
}
int RenderTexture::height() const noexcept {
return h;
}
std::pair<int, int> RenderTexture::calcRenderSize(int w, int h) const noexcept {
int rw, rh;
if (w == 0 && h == 0) {
rw = width();
rh = height();
} else if (w == 0) {
rw = (h * width() / height());
rh = h;
} else if (h == 0) {
rw = w;
rh = (w * height() / width());
} else {
rw = w;
rh = h;
}
return {rw, rh};
}

76
src/render/window.cpp Normal file
View File

@ -0,0 +1,76 @@
#ifndef HEADER_ARRAS_RENDER_WINDOW_HPP
#define HEADER_ARRAS_RENDER_WINDOW_HPP
#include "render.h"
#define Pi 3.14159265358979323846
using namespace arras;
RenderWindow::RenderWindow(RenderWindow&& rd)
: w(rd.w), h(rd.h), window(rd.window), renderer(rd.renderer) {
rd.renderer = nullptr;
rd.window = nullptr;
}
RenderWindow::RenderWindow(int w, int h): w(w), h(h) {
if (SDL_CreateWindowAndRenderer(w, h, SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI, &window, &renderer) != 0) {
throw std::runtime_error(
fmt::format("SDL_CreateWindowAndRenderer() failed: {}", SDL_GetError()));
}
}
RenderWindow::~RenderWindow() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
}
SDL_Renderer* RenderWindow::nativeHandle() const noexcept {
return renderer;
}
void RenderWindow::renderTextureAt(const RenderTexture& t, const Vec2& pos) const {
if (SDL_RenderCopyF(renderer,
t.nativeHandle(),
NULL,
makeFRect(pos, {t.width(), t.height()}).get())) {
throw std::runtime_error(fmt::format("SDL_RenderCopy() failed: {}", SDL_GetError()));
}
}
void RenderWindow::renderTextureAt(const RenderTexture& t,
const Vec2& pos,
const Vec2& direction) const {
if (SDL_RenderCopyExF(renderer,
t.nativeHandle(),
NULL,
makeFRect(pos, {t.width(), t.height()}).get(),
-asAngle(direction) * 180 / Pi,
nullptr,
SDL_FLIP_NONE)) {
throw std::runtime_error(fmt::format("SDL_RenderCopy() failed: {}", SDL_GetError()));
}
}
void RenderWindow::present() const noexcept {
SDL_RenderPresent(renderer);
}
void RenderWindow::clear(const Color& c) const {
if (SDL_SetRenderDrawColor(renderer, c.r, c.g, c.b, c.a)) {
throw std::runtime_error(
fmt::format("SDL_SetRenderDrawColor() failed: {}", SDL_GetError()));
}
if (SDL_RenderClear(renderer)) {
throw std::runtime_error(fmt::format("SDL_RenderClear() failed: {}", SDL_GetError()));
}
}
int RenderWindow::width() const noexcept {
return w;
}
int RenderWindow::height() const noexcept {
return h;
}
#endif

View File

@ -1,4 +1,4 @@
#include "2d.hpp"
#include "2d.h"
#include "test/u.hpp"
#include <functional>
#include <initializer_list>
@ -6,6 +6,7 @@
namespace {
AddTestCase _(1, "2d.hpp", [](TestCase& t) {
using namespace arras;
t.expectEq<Float>([] { return cross({1, 2}, {4, 1}); }, -7);
t.expectEq<Float>([] { return cross({.5, 2.5}, {4, 1.5}); }, -9.25);

10
test/cases/objects.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "objects.hpp"
#include "test/u.hpp"
namespace {
AddTestCase _(1, "objects.hpp", [](TestCase& t) {
});
}

View File

@ -4,13 +4,31 @@ set_version("0.0a0")
set_languages("c++17")
set_targetdir(".")
target("test")
add_requires("entt 3.11", "libsdl 2.26", "libsdl_image 2.6", "fmt 10")
add_includedirs("include", ".")
target("main")
set_default(true)
set_kind("binary")
add_files("main.cpp")
add_files("src/**/*.cpp")
add_packages("entt", "libsdl", "libsdl_image", "fmt")
set_warnings("allextra")
target("test")
set_default(false)
set_kind("binary")
set_prefixname("test-")
add_files("test/main.cpp")
add_files("test/cases/*.cpp")
add_includedirs(".")
add_files("src/**/*.cpp")
add_packages("entt", "fmt")
set_warnings("allextra")
set_optimize("none")
set_symbols("debug")
add_defines("DEBUG")
set_prefixname("test-")