SDL_Renderer backend and SDL_image texture loader

This commit is contained in:
Timerix 2024-08-01 20:47:26 +03:00
parent 7471c09452
commit 87296180ee
11 changed files with 231 additions and 81 deletions

View File

@ -1,31 +1,16 @@
# ougge
# OUGGE
A game engine or something, idk.
## Installation
1. Clone the repository
1. Clone the repository.
```sh
git clone --recurse-submodules https://timerix.ddns.net:3322/Timerix/ougge.git
```
2. Install [cbuild](https://timerix.ddns.net:3322/Timerix/cbuild.git)
3. Install **SDL2** from package manager or compile it from source.
**If you are using msys, switch to mingw64 sh.**
```sh
git clone https://github.com/libsdl-org/SDL.git
cd SDL
./configure
make -j [number of cpu threads]
```
Then you can install it systemwide (on **Linux**):
```sh
sudo make install
```
or copy to ./dependencies/precompiled/ (on **Windows**):
```sh
mkdir -p ../ougge/dependencies/precompiled/
cp ./build/.libs/SDL2.dll ../ougge/dependencies/precompiled/
```
If it doesn't work, read [SDL/INSTALL.txt](https://github.com/libsdl-org/SDL/blob/SDL2/INSTALL.txt) and [SDL/docs/README.md](https://github.com/libsdl-org/SDL/blob/SDL2/docs/README.md).
4. Symlink SDL headers directory to `dependencies/include`
2. Install [cbuild](https://timerix.ddns.net:3322/Timerix/cbuild.git).
3. Install [SDL2](https://github.com/libsdl-org/SDL) and [SDL2_image](https://github.com/libsdl-org/SDL_image).
- On **Linux** install shared libraries from a package manager or compile them from source.
- On **Windows** download pre-built dll's from github releases and put them into `dependencies/precompiled/`.
4. Symlink SDL headers directory to `dependencies/include`.
```sh
cd ../ougge
ln -s SDL2_HEADERS_DIRECTORY_ABSOLUTE_PATH -T dependencies/include/SDL2

View File

@ -16,7 +16,7 @@ SRC_CPP="imgui.cpp
imgui_tables.cpp
imgui_widgets.cpp
backends/imgui_impl_sdl2.cpp
backends/imgui_impl_opengl3.cpp"
backends/imgui_impl_sdlrenderer2.cpp"
# Directory with dependency configs.
# See cbuild/example_dependency_configs

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -35,12 +35,12 @@ case "$OS" in
WINDOWS)
EXEC_FILE="$PROJECT.exe"
SHARED_LIB_FILE="$PROJECT.dll"
LINKER_LIBS="-lopengl32 -lpthread"
LINKER_LIBS=""
;;
LINUX)
EXEC_FILE="$PROJECT"
SHARED_LIB_FILE="$PROJECT.so"
LINKER_LIBS="-lSDL2 -lGL"
LINKER_LIBS="-lSDL2 -lSDL2_image"
;;
*)
error "operating system $OS has no configuration variants"

View File

@ -1,16 +1,17 @@
#include <backends/imgui_impl_sdl2.h>
#include <backends/imgui_impl_opengl3.h>
#include <backends/imgui_impl_sdlrenderer2.h>
#include <iostream>
#include "MainWindow.hpp"
#include "../exceptions.hpp"
#include "../format.hpp"
#include "../Resources/fonts.hpp"
#include "../Resources/textures.hpp"
namespace ougge::GUI {
f32 MainWindow::getDPI(){
int w=0, h=0;
SDL_GL_GetDrawableSize(sdl_window, &w, &h);
SDL_GetRendererOutputSize(sdl_renderer, &w, &h);
int sim_w=0, sim_h=0;
SDL_GetWindowSize(sdl_window, &sim_w, &sim_h);
f32 wdpi=(f32)w / sim_w;
@ -20,40 +21,35 @@ f32 MainWindow::getDPI(){
}
void MainWindow::init(const char* window_title){
SDL_TRY(SDL_Init(SDL_INIT_VIDEO));
SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING));
SDL_version v;
SDL_GetVersion(&v);
std::cout<<format("SDL version: %u.%u.%u\n", v.major, v.minor, v.patch);
// GL 3.0 + GLSL 130
const char* glsl_version = "#version 130";
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0));
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE));
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3));
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0));
// From 2.0.18: Enable native IME.
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
// Create window with graphics context
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1));
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24));
SDL_TRY( SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8));
SDL_WindowFlags window_flags = (SDL_WindowFlags)(
SDL_WINDOW_OPENGL |
SDL_WINDOW_RESIZABLE |
SDL_WINDOW_ALLOW_HIGHDPI);
SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
);
sdl_window = SDL_CreateWindow(window_title,
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
1280, 720, window_flags);
if(sdl_window == nullptr)
throw SDLException();
gl_context = SDL_GL_CreateContext(sdl_window);
if(gl_context == nullptr)
SDL_RendererFlags renderer_flags = (SDL_RendererFlags)(
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, renderer_flags);
if(sdl_renderer == nullptr)
throw SDLException();
SDL_TRY( SDL_GL_MakeCurrent(sdl_window, gl_context));
SDL_TRY( SDL_GL_SetSwapInterval(1)); // Enable vsync
SDL_RendererInfo info;
SDL_GetRendererInfo(sdl_renderer, &info);
std::cout<<"Current SDL_Renderer driver: "<<info.name<<std::endl;
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
@ -68,9 +64,9 @@ void MainWindow::init(const char* window_title){
io.ConfigWindowsMoveFromTitleBarOnly = true;
// Setup Platform/Renderer backends
if(ImGui_ImplSDL2_InitForOpenGL(sdl_window, gl_context) != true)
if(!ImGui_ImplSDL2_InitForSDLRenderer(sdl_window, sdl_renderer))
throw SDLException();
if(ImGui_ImplOpenGL3_Init(glsl_version) != true)
if(!ImGui_ImplSDLRenderer2_Init(sdl_renderer))
throw SDLException();
// Setup Dear ImGui style
@ -150,7 +146,7 @@ void MainWindow::draw_ui(){
void MainWindow::draw_frame(){
// Start the Dear ImGui frame
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
@ -159,25 +155,18 @@ void MainWindow::draw_frame(){
// Rendering
ImGui::Render();
ImGuiIO& io = ImGui::GetIO();
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
SDL_RenderSetScale(sdl_renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
SDL_SetRenderDrawColor(sdl_renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
SDL_RenderClear(sdl_renderer);
// Update and Render additional Platform Windows
// (Platform functions may change the current OpenGL context, so we save/restore it to make it easier to paste this code elsewhere.
// For this specific demo app we could also call SDL_GL_MakeCurrent(window, gl_context) directly)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
}
SDL_GL_SwapWindow(sdl_window);
// Resources::getCached
Resources::Texture sprite(sdl_renderer);
sprite.loadFrom(Resources::getResource("tutel.png"));
sprite.render(SDL_FRectConstruct(100, 100, 400, 400));
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), sdl_renderer);
// Swap buffers
SDL_RenderPresent(sdl_renderer);
}
void MainWindow::startAndWait(){
@ -193,6 +182,7 @@ void MainWindow::startAndWait(){
// main loop
while(loop_running){
// waits for events
main_loop_wait_for_input = false;
poll_events(frame_updates_requested, main_loop_wait_for_input);
if(frame_updates_requested==0)
@ -228,10 +218,10 @@ void MainWindow::close(){
}
void MainWindow::destroy(){
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDLRenderer2_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_GL_DeleteContext(gl_context);
SDL_DestroyRenderer(sdl_renderer);
SDL_DestroyWindow(sdl_window);
SDL_Quit();
}

View File

@ -1,7 +1,6 @@
#pragma once
#include <SDL.h>
#include <SDL_opengl.h>
#include <imgui.h>
#include "../std.hpp"
@ -27,7 +26,7 @@ private:
bool show_demo_window = false;
bool show_metrics_window = false;
SDL_Window* sdl_window = nullptr;
SDL_GLContext gl_context = nullptr;
SDL_Renderer* sdl_renderer = nullptr;
public:
void init(const char* window_title);

View File

@ -1,7 +1,7 @@
#include <unordered_map>
#include <fstream>
#include <sstream>
#include "../UsefulException.hpp"
#include "../exceptions.hpp"
#include "../format.hpp"
#include "Resources.hpp"
#include "embedded_resources.h"
@ -19,16 +19,27 @@ MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
setp(p, p + n);
}
class MemoryStreamRead : public std::istream {
public:
MemoryStreamRead(const void* p, const std::size_t n)
: std::istream(new MemoryStreamBuf((void*)p, n))
{}
std::istream::pos_type MemoryStreamBuf::seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which)
{
if (dir == std::ios_base::cur)
gbump(off);
else if (dir == std::ios_base::end)
setg(eback(), egptr() + off, egptr());
else if (dir == std::ios_base::beg)
setg(eback(), eback() + off, egptr());
return gptr() - eback();
}
virtual ~MemoryStreamRead(){
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
: std::istream(new MemoryStreamBuf((void*)p, n))
{}
MemoryStreamRead::~MemoryStreamRead(){
delete rdbuf();
}
};
}
static std::unordered_map<std::string, Resource>* _resourceMap = nullptr;

View File

@ -27,8 +27,19 @@ public:
class MemoryStreamBuf : public std::streambuf {
public:
MemoryStreamBuf(void* p, const std::size_t n);
virtual std::istream::pos_type seekoff(
std::istream::off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which);
};
class MemoryStreamRead : public std::istream {
public:
MemoryStreamRead(const void* p, const std::size_t n);
virtual ~MemoryStreamRead();
};
Resource& getResource(const std::string& path);

105
src/Resources/textures.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "textures.hpp"
#include <SDL_image.h>
#include "../exceptions.hpp"
namespace ougge::Resources {
Texture::Texture(SDL_Renderer* renderer)
: renderer(renderer), texture(nullptr), w(0), h(0)
{}
Texture::~Texture(){
SDL_DestroyTexture(texture);
}
void Texture::loadFrom(const Resource& r){
auto s = r.openStream();
loadFrom(*s, r.size);
}
void Texture::loadFrom(std::istream& s, size_t size){
if(texture)
throw UsefulException("texture has been loaded already");
SDL_RWops* sdl_stream = SDL_RWFromIStream(s, size);
if(!sdl_stream)
throw SDLException();
texture = IMG_LoadTexture_RW(renderer, sdl_stream, 1);
if(!texture)
throw IMGException();
SDL_TRY(SDL_QueryTexture(texture, nullptr, nullptr, &w, &h));
}
SDL_RenderCopyExF_Params::SDL_RenderCopyExF_Params()
: rotation_angle(0), flip(SDL_FLIP_NONE)
{}
void Texture::render(const SDL_FRect& target_section){
SDL_TRY(
SDL_RenderCopyF(renderer, texture, nullptr, &target_section)
);
}
void Texture::render(const SDL_FRect& target_section, const SDL_Rect& texture_section){
SDL_TRY(
SDL_RenderCopyF(renderer, texture, &texture_section, &target_section)
);
}
void Texture::render(const SDL_RenderCopyExF_Params& p){
SDL_TRY(
SDL_RenderCopyExF(renderer, texture,
optional_value_ptr_or_null(p.texture_section),
optional_value_ptr_or_null(p.target_section),
p.rotation_angle,
optional_value_ptr_or_null(p.rotation_center),
p.flip
)
)
}
static Sint64 istream_size(SDL_RWops* context){
return (Sint64)(size_t)context->hidden.unknown.data2;
}
static Sint64 istream_seek(SDL_RWops* context, Sint64 offset, int whence){
std::istream* stream = (std::istream*)context->hidden.unknown.data1;
switch(whence){
case SEEK_SET: stream->seekg(offset, std::ios::beg); break;
case SEEK_CUR: stream->seekg(offset, std::ios::cur); break;
case SEEK_END: stream->seekg(offset, std::ios::end); break;
default: break;
}
return stream->fail() ? -1 : (Sint64)stream->tellg();
}
static size_t istream_read(SDL_RWops* context, void *ptr, size_t size, size_t maxnum){
if(size == 0)
return -1;
std::istream* stream = (std::istream*)context->hidden.unknown.data1;
stream->read((char*)ptr, size * maxnum);
return stream->bad() ? -1 : stream->gcount() / size;
}
static int istream_close(SDL_RWops* context){
if (context)
SDL_FreeRW(context);
return 0;
}
SDL_RWops* SDL_RWFromIStream(std::istream& stream, size_t size){
SDL_RWops* rwops = SDL_AllocRW();
if(rwops) {
rwops->size = istream_size;
rwops->seek = istream_seek;
rwops->read = istream_read;
rwops->write = nullptr;
rwops->close = istream_close;
rwops->hidden.unknown.data1 = &stream;
rwops->hidden.unknown.data2 = (void*)size;
rwops->type = SDL_RWOPS_UNKNOWN;
}
return rwops;
}
}

View File

@ -0,0 +1,47 @@
#pragma once
#include <string>
#include <iostream>
#include <optional>
#include <SDL.h>
#include "Resources.hpp"
namespace ougge::Resources {
#define SDL_RectConstruct(X, Y, W, H) (SDL_Rect){X, Y, W, H}
#define SDL_FRectConstruct(X, Y, W, H) (SDL_FRect){X, Y, W, H}
#define SDL_PointConstruct(X, Y) (SDL_Point){X, Y, W, H}
#define SDL_FPointConstruct(X, Y) (SDL_FPoint){X, Y, W, H}
#define optional_value_ptr_or_null(OPT) (OPT ? &(*OPT) : nullptr)
SDL_RWops* SDL_RWFromIStream(std::istream& stream, size_t size);
struct SDL_RenderCopyExF_Params {
std::optional<SDL_Rect> texture_section;
std::optional<SDL_FRect> target_section;
std::optional<SDL_FPoint> rotation_center;
double rotation_angle;
SDL_RendererFlip flip;
SDL_RenderCopyExF_Params();
};
struct Texture {
SDL_Renderer* renderer;
SDL_Texture* texture;
int w;
int h;
Texture(SDL_Renderer* renderer);
~Texture();
void loadFrom(const Resource& r);
void loadFrom(std::istream& s, size_t size);
void render(const SDL_FRect& target_section);
void render(const SDL_FRect& target_section, const SDL_Rect& texture_section);
void render(const SDL_RenderCopyExF_Params& params);
};
}

View File

@ -3,6 +3,8 @@
#include "std.hpp"
#include "GUI/MainWindow.hpp"
#include "Resources/Resources.hpp"
#include "format.hpp"
#include "exceptions.hpp"
using namespace ougge;