@@ -62,7 +62,6 @@ set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib;${CMAKE_INSTALL_PREFIX}/lib | |||
add_subdirectory(third-party) | |||
add_subdirectory(tracy-tools) | |||
add_subdirectory(libcygnet) | |||
add_subdirectory(libswan) | |||
add_subdirectory(core.mod) | |||
@@ -1,30 +0,0 @@ | |||
add_library(cygnet SHARED | |||
src/builtins.cc | |||
src/glutil.cc | |||
src/GlWrappers.cc | |||
src/Image.cc | |||
src/RenderQueue.cc | |||
src/Window.cc) | |||
target_link_libraries(cygnet PUBLIC SDL2 SDL2_image GLESv2) | |||
target_include_directories(cygnet | |||
PUBLIC include | |||
PRIVATE include/cygnet) | |||
add_executable(cygnet-hello-triangle | |||
samples/hello-triangle/hello-triangle.cc) | |||
target_link_libraries(cygnet-hello-triangle PUBLIC cygnet) | |||
add_executable(cygnet-hello-texture | |||
samples/hello-texture/hello-texture.cc) | |||
target_link_libraries(cygnet-hello-texture PUBLIC cygnet) | |||
add_executable(cygnet-game | |||
samples/game/game.cc) | |||
target_link_libraries(cygnet-game PUBLIC cygnet) | |||
set(assets | |||
samples/game/assets/player.png) | |||
foreach(a ${assets}) | |||
configure_file("${a}" "${a}" COPYONLY) | |||
endforeach(a) | |||
@@ -1,78 +0,0 @@ | |||
#pragma once | |||
#include <vector> | |||
#include <initializer_list> | |||
#include <functional> | |||
#include <SDL_opengles2.h> | |||
#include "util.h" | |||
namespace Cygnet { | |||
class GlShader: NonCopyable { | |||
public: | |||
enum class Type { | |||
VERTEX, | |||
FRAGMENT, | |||
}; | |||
GlShader(Type type, const char *source); | |||
~GlShader(); | |||
GLuint id() const { return id_; } | |||
private: | |||
GLuint id_; | |||
}; | |||
class GlProgram: NonCopyable { | |||
public: | |||
template <typename... T, typename = std::enable_if_t<std::conjunction_v<std::is_same<T, GlShader>...>>> | |||
GlProgram(const T &... shaders): GlProgram() { (addShader(shaders), ...); link(); } | |||
GlProgram() { id_ = glCreateProgram(); } | |||
~GlProgram(); | |||
void addShader(const GlShader &shader) { glAttachShader(id_, shader.id()); } | |||
void link(); | |||
void use() { glUseProgram(id_); } | |||
GLuint id() { return id_; } | |||
GLint attribLoc(const char *name); | |||
GLint attribLoc(const char *name, GLuint index); | |||
GLint uniformLoc(const char *name); | |||
private: | |||
GLuint id_; | |||
}; | |||
class GlTexture: NonCopyable { | |||
public: | |||
GlTexture(); | |||
void bind(); | |||
void upload(GLsizei width, GLsizei height, void *data, | |||
GLenum format, GLenum type = GL_UNSIGNED_BYTE); | |||
GLuint id() { return id_; } | |||
int width() { return w_; } | |||
int height() { return h_; } | |||
private: | |||
GLuint id_; | |||
int w_; | |||
int h_; | |||
}; | |||
inline GLint GlProgram::attribLoc(const char *name) { | |||
return glGetAttribLocation(id_, name); | |||
} | |||
inline GLint GlProgram::attribLoc(const char *name, GLuint index) { | |||
glBindAttribLocation(id_, index, name); | |||
return index; | |||
} | |||
inline GLint GlProgram::uniformLoc(const char *name) { | |||
return glGetUniformLocation(id_, name); | |||
} | |||
} |
@@ -1,27 +0,0 @@ | |||
#pragma once | |||
#include <memory> | |||
#include "GlWrappers.h" | |||
namespace Cygnet { | |||
class Image { | |||
public: | |||
Image(std::string path); | |||
GlTexture &texture(); | |||
int width() { return w_; } | |||
int height() { return h_; } | |||
private: | |||
std::string path_; | |||
int w_, h_, pitch_; | |||
std::unique_ptr<unsigned char[]> bytes_; | |||
GlTexture tex_; | |||
bool tex_dirty_ = true; | |||
}; | |||
} |
@@ -1,68 +0,0 @@ | |||
#pragma once | |||
#include <vector> | |||
#include "GlWrappers.h" | |||
namespace Cygnet { | |||
class RenderQueue { | |||
public: | |||
struct Locs { | |||
GLint transform; | |||
GLint position; | |||
GLint texCoord; | |||
GLint tex; | |||
}; | |||
RenderQueue(Locs locs, float scale): | |||
locs_(std::move(locs)), pixScale_(scale) {}; | |||
RenderQueue(GlProgram &prog, float scale): | |||
RenderQueue({ | |||
prog.uniformLoc("transform"), | |||
prog.attribLoc("position"), | |||
prog.attribLoc("texCoord"), | |||
prog.uniformLoc("tex"), | |||
}, scale) {} | |||
void show(GlTexture &tex, float x, float y) { | |||
show(tex.id(), x, y, tex.width(), tex.height()); | |||
} | |||
void show(GlTexture &tex, float x, float y, float sx, float sy) { | |||
show(tex.id(), x, y, tex.width() * sx, tex.height() * sy); | |||
} | |||
void show(GlTexture &tex, float x, float y, float sx, float sy, float w, float h) { | |||
show(tex.id(), x, y, w * sx, h * sy); | |||
} | |||
void show(GLuint tex, float x, float y, float w, float h) { | |||
queue_.push_back({ tex, x, y, w * pixScale_, h * pixScale_ }); | |||
} | |||
float getScaleX() { return mat_[0]; } | |||
float getScaleY() { return -mat_[4]; } | |||
float getTranslateX() { return mat_[3]; } | |||
float getTranslateY() { return mat_[5]; } | |||
void setScale(float sx, float sy) { mat_[0] = sx; mat_[4] = -sy; } | |||
void setTranslate(float tx, float ty) { mat_[2] = tx; mat_[5] = ty; } | |||
void draw(); | |||
private: | |||
struct Entry { | |||
GLuint tex; | |||
float x, y; | |||
float w, h; | |||
}; | |||
Locs locs_; | |||
float pixScale_; | |||
GLfloat mat_[9] = { | |||
1, 0, 0, // scaleX, 0, translateX, | |||
0, -1, 0, // 0, -scaleY, translateY, | |||
0, 0, 1, // 0, 0, 1 | |||
}; | |||
std::vector<Entry> queue_; | |||
}; | |||
} |
@@ -1,39 +0,0 @@ | |||
#pragma once | |||
#include <SDL.h> | |||
#include <stdint.h> | |||
#include "util.h" | |||
namespace Cygnet { | |||
class GlTexture; | |||
class Window { | |||
public: | |||
Window(const char *name, int width, int height); | |||
~Window(); | |||
void makeCurrent(); | |||
void clear(); | |||
void flip(); | |||
int width() { return w_; } | |||
int height() { return h_; } | |||
// xScale and yScale are what drawn objects need to be scaled with | |||
// in order to have square pixels. | |||
float xScale() { return xScale_; } | |||
float yScale() { return yScale_; } | |||
void onResize(int w, int h); | |||
private: | |||
CPtr<SDL_Window, SDL_DestroyWindow> win_; | |||
SDL_GLContext glctx_; | |||
int w_; | |||
int h_; | |||
float yScale_; | |||
float xScale_; | |||
}; | |||
} |
@@ -1,11 +0,0 @@ | |||
#include <optional> | |||
#include "GlWrappers.h" | |||
namespace Cygnet { | |||
const GlShader &builtinTextureVertex(); | |||
const GlShader &builtinTextureFragment(); | |||
const GlShader &builtinWhiteFragment(); | |||
} |
@@ -1,9 +0,0 @@ | |||
#pragma once | |||
namespace Cygnet { | |||
const char *glErrorString(int err); | |||
void glCheck(); | |||
void sdlAssert(bool val); | |||
} |
@@ -1,45 +0,0 @@ | |||
#pragma once | |||
#include <memory> | |||
/* | |||
* This file mostly just contains copy-pasted stuff from libswan. | |||
* I don't love the code duplication, but it feels overkill to have a | |||
* library which both libcygnet and libswan depends on just for this stuff. | |||
*/ | |||
namespace Cygnet { | |||
// Inherit from this class to make a class non-copyable | |||
class NonCopyable { | |||
public: | |||
NonCopyable(const NonCopyable &) = delete; | |||
NonCopyable(NonCopyable &&) noexcept = default; | |||
NonCopyable &operator=(const NonCopyable &) = delete; | |||
NonCopyable &operator=(NonCopyable &&) = default; | |||
protected: | |||
NonCopyable() = default; | |||
~NonCopyable() = default; | |||
}; | |||
// Take a deleter function, turn it into a class with an operator() for unique_ptr | |||
template<typename T, void (*Func)(T *)> | |||
class CPtrDeleter { | |||
public: | |||
void operator()(T *ptr) { Func(ptr); } | |||
}; | |||
// This is just a bit nicer to use than using unique_ptr directly | |||
template<typename T, void (*Func)(T *)> | |||
using CPtr = std::unique_ptr<T, CPtrDeleter<T, Func>>; | |||
// Take a function, run it when the object goes out of scope | |||
template<void (*Func)()> | |||
class Deferred: NonCopyable { | |||
public: | |||
Deferred() = default; | |||
~Deferred() { Func(); } | |||
}; | |||
} |
@@ -1,174 +0,0 @@ | |||
#include <cygnet/Window.h> | |||
#include <cygnet/GlWrappers.h> | |||
#include <cygnet/builtins.h> | |||
#include <cygnet/glutil.h> | |||
#include <cygnet/Image.h> | |||
#include <cygnet/RenderQueue.h> | |||
#include <stdio.h> | |||
#include <memory> | |||
#include <vector> | |||
#include <iostream> | |||
const char *vertexShader = R"( | |||
uniform mat3 transform; | |||
attribute vec2 position; | |||
attribute vec2 texCoord; | |||
varying vec2 v_texCoord; | |||
void main() { | |||
vec3 pos = transform * vec3(position, 0); | |||
gl_Position = vec4(pos.x, pos.y, 0, 1); | |||
v_texCoord = texCoord; | |||
} | |||
)"; | |||
const char *fragmentShader = R"( | |||
precision mediump float; | |||
varying vec2 v_texCoord; | |||
uniform sampler2D tex; | |||
void main() { | |||
gl_FragColor = texture2D(tex, v_texCoord); | |||
} | |||
)"; | |||
enum class Key { | |||
UP, DOWN, LEFT, RIGHT, NONE, | |||
}; | |||
struct State { | |||
bool keys[(int)Key::NONE]{}; | |||
Cygnet::Window &win; | |||
Cygnet::GlProgram &program; | |||
Cygnet::RenderQueue &q; | |||
}; | |||
class Entity { | |||
public: | |||
virtual ~Entity() = default; | |||
virtual void update(State &state, float dt) = 0; | |||
virtual void draw(State &state) = 0; | |||
}; | |||
class PlayerEntity: public Entity { | |||
public: | |||
PlayerEntity(float x, float y): x_(x), y_(y) {} | |||
void update(State &state, float dt) override { | |||
float fx{}, fy{}; | |||
if (state.keys[(int)Key::LEFT]) | |||
fx -= 1; | |||
if (state.keys[(int)Key::RIGHT]) | |||
fx += 1; | |||
if (state.keys[(int)Key::UP]) | |||
fy -= 1; | |||
if (state.keys[(int)Key::DOWN]) | |||
fy += 1; | |||
fy += vy_ * -0.9; | |||
fx += vx_ * -0.9; | |||
vx_ += fx * dt; | |||
vy_ += fy * dt; | |||
x_ += vx_ * dt; | |||
y_ += vy_ * dt; | |||
} | |||
void draw(State &state) override { | |||
state.q.show(image_.texture(), x_, y_); | |||
} | |||
private: | |||
float x_, y_; | |||
float vx_{}, vy_{}; | |||
Cygnet::Image image_{"libcygnet/samples/game/assets/player.png"}; | |||
}; | |||
Key keyFromSym(SDL_Keysym sym) { | |||
switch (sym.scancode) { | |||
case SDL_SCANCODE_W: | |||
return Key::UP; | |||
case SDL_SCANCODE_A: | |||
return Key::LEFT; | |||
case SDL_SCANCODE_S: | |||
return Key::DOWN; | |||
case SDL_SCANCODE_D: | |||
return Key::RIGHT; | |||
default: | |||
return Key::NONE; | |||
} | |||
} | |||
int main() { | |||
SDL_Init(SDL_INIT_VIDEO); | |||
Cygnet::Deferred<SDL_Quit> sdl; | |||
Cygnet::Window win("Game", 640, 480); | |||
Cygnet::GlProgram program( | |||
Cygnet::GlShader(Cygnet::GlShader::Type::VERTEX, vertexShader), | |||
Cygnet::GlShader(Cygnet::GlShader::Type::FRAGMENT, fragmentShader)); | |||
program.use(); | |||
Cygnet::RenderQueue q(program, 1/32.0); | |||
State state{ | |||
.keys{}, | |||
.win = win, | |||
.program = program, | |||
.q = q, | |||
}; | |||
std::vector<std::unique_ptr<Entity>> entities; | |||
entities.emplace_back(std::make_unique<PlayerEntity>(0, 0)); | |||
SDL_Event evt; | |||
while (true) { | |||
while (SDL_PollEvent(&evt)) { | |||
switch (evt.type) { | |||
case SDL_QUIT: | |||
goto exit; | |||
break; | |||
case SDL_WINDOWEVENT: | |||
if (evt.window.event == SDL_WINDOWEVENT_RESIZED) { | |||
win.onResize(evt.window.data1, evt.window.data2); | |||
} | |||
break; | |||
case SDL_KEYDOWN: | |||
{ | |||
Key key = keyFromSym(evt.key.keysym); | |||
if (key != Key::NONE) { | |||
state.keys[(int)key] = true; | |||
} | |||
} | |||
break; | |||
case SDL_KEYUP: | |||
{ | |||
Key key = keyFromSym(evt.key.keysym); | |||
if (key != Key::NONE) { | |||
state.keys[(int)key] = false; | |||
} | |||
} | |||
break; | |||
} | |||
} | |||
win.clear(); | |||
for (auto &ent: entities) { | |||
ent->update(state, 1/60.0); | |||
} | |||
for (auto &ent: entities) { | |||
ent->draw(state); | |||
} | |||
q.setScale(win.xScale() * 0.5, win.yScale() * 0.5); | |||
q.draw(); | |||
win.flip(); | |||
} | |||
exit: ; | |||
} |
@@ -1,76 +0,0 @@ | |||
#include <cygnet/Window.h> | |||
#include <cygnet/GlWrappers.h> | |||
#include <cygnet/builtins.h> | |||
#include <cygnet/glutil.h> | |||
#include <iostream> | |||
int main() { | |||
SDL_Init(SDL_INIT_VIDEO); | |||
Cygnet::Deferred<SDL_Quit> sdl; | |||
Cygnet::Window win("Hello Texture", 640, 480); | |||
Cygnet::GlProgram program(Cygnet::builtinTextureVertex(), Cygnet::builtinTextureFragment()); | |||
program.use(); | |||
GLfloat vertexes[] = { | |||
-0.5f, 0.5f, 0.0f, // pos 0: top left | |||
0.0f, 0.0f, // tex 0: top left | |||
-0.5f, -0.5f, 0.0f, // pos 1: bottom left | |||
0.0f, 1.0f, // tex 1: bottom left | |||
0.5f, -0.5f, 0.0f, // pos 2: bottom right | |||
1.0f, 1.0f, // tex 2: bottom right | |||
0.5f, 0.5f, 0.0f, // pos 3: top right | |||
1.0f, 0.0f, // tex 3: top right | |||
}; | |||
GLushort indexes[] = { | |||
0, 1, 2, // top left -> bottom left -> bottom right | |||
2, 3, 0, // bottom right -> top right -> top left | |||
}; | |||
uint8_t image[] = { | |||
0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, 0xff, 0x00, 0xba, 0, 0, 0, | |||
0xaa, 0xaa, 0xaa, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0, 0, 0, | |||
0xa0, 0x55, 0x77, 0x00, 0xf0, 0x0f, 0xff, 0x00, 0xff, 0, 0, 0, | |||
}; | |||
Cygnet::GlTexture tex; | |||
tex.upload(3, 3, image, GL_RGB); | |||
GLint positionLoc = program.attribLoc("position", 0); | |||
GLint texCoordLoc = program.attribLoc("texCoord", 1); | |||
GLint texLoc = program.uniformLoc("tex"); | |||
glUniform1i(texLoc, 0); | |||
// Draw loop | |||
while (true) { | |||
SDL_Event evt; | |||
while (SDL_PollEvent(&evt)) { | |||
switch (evt.type) { | |||
case SDL_QUIT: | |||
goto exit; | |||
break; | |||
} | |||
} | |||
win.clear(); | |||
glVertexAttribPointer(positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertexes); | |||
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &vertexes[3]); | |||
Cygnet::glCheck(); | |||
glEnableVertexAttribArray(positionLoc); | |||
glEnableVertexAttribArray(texCoordLoc); | |||
Cygnet::glCheck(); | |||
tex.bind(); | |||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indexes); | |||
Cygnet::glCheck(); | |||
win.flip(); | |||
} | |||
exit: | |||
return EXIT_SUCCESS; | |||
} |
@@ -1,58 +0,0 @@ | |||
#include <cygnet/Window.h> | |||
#include <cygnet/GlWrappers.h> | |||
#include <iostream> | |||
const char *vertexSource = R"( | |||
attribute vec4 position; | |||
void main() { | |||
gl_Position = vec4(position.xyz, 1.0); | |||
} | |||
)"; | |||
const char *fragmentSource = R"( | |||
precision mediump float; | |||
void main() { | |||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); | |||
} | |||
)"; | |||
int main() { | |||
SDL_Init(SDL_INIT_VIDEO); | |||
Cygnet::Deferred<SDL_Quit> sdl; | |||
Cygnet::Window win("Hello Triangle", 640, 480); | |||
Cygnet::GlShader vertex(Cygnet::GlShader::Type::VERTEX, vertexSource); | |||
Cygnet::GlShader fragment(Cygnet::GlShader::Type::FRAGMENT, fragmentSource); | |||
Cygnet::GlProgram program(vertex, fragment); | |||
GLuint positionAttrib = program.attribLoc("position"); | |||
program.use(); | |||
GLfloat vertixes[] = { | |||
0.0, 0.5, 0.0, | |||
-0.5, -0.5, 0.0, | |||
0.5, -0.5, 0.0, | |||
}; | |||
// Draw loop | |||
while (true) { | |||
SDL_Event evt; | |||
while (SDL_PollEvent(&evt)) { | |||
switch (evt.type) { | |||
case SDL_QUIT: | |||
goto exit; | |||
break; | |||
} | |||
} | |||
win.clear(); | |||
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, 0, vertixes); | |||
glEnableVertexAttribArray(positionAttrib); | |||
glDrawArrays(GL_TRIANGLES, 0, 3); | |||
win.flip(); | |||
} | |||
exit: | |||
return EXIT_SUCCESS; | |||
} |
@@ -1,98 +0,0 @@ | |||
#include "GlWrappers.h" | |||
#include <iostream> | |||
#include <stdexcept> | |||
#include "glutil.h" | |||
namespace Cygnet { | |||
GlShader::GlShader(Type type, const char *source) { | |||
switch (type) { | |||
case Type::VERTEX: | |||
id_ = glCreateShader(GL_VERTEX_SHADER); | |||
glCheck(); | |||
std::cerr << "compiling vertex shader...\n"; | |||
break; | |||
case Type::FRAGMENT: | |||
id_ = glCreateShader(GL_FRAGMENT_SHADER); | |||
glCheck(); | |||
std::cerr << "compiling fragment shader...\n"; | |||
break; | |||
} | |||
glShaderSource(id_, 1, &source, NULL); | |||
glCheck(); | |||
glCompileShader(id_); | |||
glCheck(); | |||
char log[4096]; | |||
GLsizei length = 0; | |||
glGetShaderInfoLog(id_, sizeof(log), &length, log); | |||
glCheck(); | |||
if (length != 0) { | |||
std::cerr << "Shader compile info (" << length << "):\n" << log << '\n'; | |||
} | |||
GLint status = 0; | |||
glGetShaderiv(id_, GL_COMPILE_STATUS, &status); | |||
glCheck(); | |||
if (status == GL_FALSE) { | |||
throw std::runtime_error("GL shader compilation failed."); | |||
} | |||
} | |||
GlShader::~GlShader() { | |||
glDeleteShader(id_); | |||
glCheck(); | |||
} | |||
void GlProgram::link() { | |||
std::cout << "link\n"; | |||
glLinkProgram(id_); | |||
glCheck(); | |||
char log[4096]; | |||
GLsizei length = 0; | |||
glGetProgramInfoLog(id_, sizeof(log), &length, log); | |||
glCheck(); | |||
if (length != 0) { | |||
std::cerr << "Program link info:\n" << log << '\n'; | |||
} | |||
GLint status = 0; | |||
glGetProgramiv(id_, GL_LINK_STATUS, &status); | |||
glCheck(); | |||
if (status == GL_FALSE) { | |||
throw std::runtime_error("GL program link failed."); | |||
} | |||
} | |||
GlProgram::~GlProgram() { | |||
glDeleteProgram(id_); | |||
} | |||
GlTexture::GlTexture() { | |||
glGenTextures(1, &id_); | |||
glCheck(); | |||
} | |||
void GlTexture::bind() { | |||
glActiveTexture(GL_TEXTURE0); | |||
glBindTexture(GL_TEXTURE_2D, id_); | |||
} | |||
void GlTexture::upload(GLsizei width, GLsizei height, void *data, | |||
GLenum format, GLenum type) { | |||
w_ = width; | |||
h_ = height; | |||
bind(); | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, type, data); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |||
glCheck(); | |||
} | |||
} |
@@ -1,43 +0,0 @@ | |||
#include "Image.h" | |||
#include <SDL2/SDL.h> | |||
#include <SDL2/SDL_image.h> | |||
#include <stdexcept> | |||
#include "util.h" | |||
namespace Cygnet { | |||
// TODO: Maybe this should be conditional based on endianness? | |||
static SDL_PixelFormatEnum format = SDL_PIXELFORMAT_ABGR8888; | |||
Image::Image(std::string path) { | |||
CPtr<SDL_Surface, SDL_FreeSurface> surface(IMG_Load(path.c_str())); | |||
if (!surface.get()) { | |||
throw std::runtime_error("Failed to load " + path + ": " + IMG_GetError()); | |||
} | |||
if (surface->format->format != format) { | |||
printf("Converting pixel format for %s", path.c_str()); | |||
surface.reset(SDL_ConvertSurfaceFormat(surface.get(), format, 0)); | |||
if (!surface.get()) { | |||
throw std::runtime_error("Failed convert " + path + ": " + SDL_GetError()); | |||
} | |||
} | |||
w_ = surface->w; | |||
h_ = surface->h; | |||
pitch_ = surface->pitch; | |||
bytes_.reset(new unsigned char[(size_t)pitch_ * h_]); | |||
memcpy(bytes_.get(), surface->pixels, (size_t)pitch_ * h_); | |||
} | |||
GlTexture &Image::texture() { | |||
if (tex_dirty_) { | |||
tex_.upload(w_, h_, bytes_.get(), GL_RGBA); | |||
} | |||
return tex_; | |||
} | |||
} |
@@ -1,55 +0,0 @@ | |||
#include "RenderQueue.h" | |||
#include "glutil.h" | |||
namespace Cygnet { | |||
static const GLfloat texCoords[] = { | |||
0.0f, 0.0f, // tex 0: top left | |||
0.0f, 1.0f, // tex 1: bottom left | |||
1.0f, 1.0f, // tex 2: bottom right | |||
1.0f, 0.0f, // tex 3: top right | |||
}; | |||
static const GLushort indexes[] = { | |||
0, 1, 2, // top left -> bottom left -> bottom right | |||
2, 3, 0, // bottom right -> top right -> top left | |||
}; | |||
void RenderQueue::draw() { | |||
glUniform1i(locs_.tex, 0); | |||
glVertexAttribPointer(locs_.texCoord, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), texCoords); | |||
glEnableVertexAttribArray(locs_.texCoord); | |||
glCheck(); | |||
glUniformMatrix3fv(locs_.transform, 1, GL_TRUE, mat_); | |||
glCheck(); | |||
glActiveTexture(GL_TEXTURE0); | |||
for (auto &entry: queue_) { | |||
float x = entry.x; | |||
float y = entry.y; | |||
float w = entry.w; | |||
float h = entry.h; | |||
GLfloat vertexes[] = { | |||
x, y, // top left | |||
x, y + h, // bottom left | |||
x + w, y + h, // bottom right | |||
x + w, y, // top right | |||
}; | |||
glVertexAttribPointer(locs_.position, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), vertexes); | |||
glEnableVertexAttribArray(locs_.position); | |||
glCheck(); | |||
glBindTexture(GL_TEXTURE_2D, entry.tex); | |||
glCheck(); | |||
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indexes); | |||
} | |||
queue_.clear(); | |||
} | |||
} |
@@ -1,59 +0,0 @@ | |||
#include "Window.h" | |||
#include <SDL_opengles2.h> | |||
#include "glutil.h" | |||
namespace Cygnet { | |||
Window::Window(const char *name, int width, int height) { | |||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); | |||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); | |||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); | |||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | |||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); | |||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); | |||
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 16); | |||
win_.reset(SDL_CreateWindow( | |||
name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, | |||
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | | |||
SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL)); | |||
sdlAssert(glctx_ = SDL_GL_CreateContext(win_.get())); | |||
makeCurrent(); | |||
glCheck(); | |||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
glEnable(GL_BLEND); | |||
glCheck(); | |||
onResize(width, height); | |||
} | |||
Window::~Window() { | |||
SDL_GL_DeleteContext(glctx_); | |||
} | |||
void Window::makeCurrent() { | |||
SDL_GL_MakeCurrent(win_.get(), glctx_); | |||
} | |||
void Window::clear() { | |||
//glClearColor(0, 0, 0, 1); | |||
glClear(GL_COLOR_BUFFER_BIT); | |||
} | |||
void Window::flip() { | |||
SDL_GL_SwapWindow(win_.get()); | |||
} | |||
void Window::onResize(int w, int h) { | |||
w_ = w; | |||
h_ = h; | |||
yScale_ = 1 / sqrt((float)h / (float)w); | |||
xScale_ = 1 / sqrt((float)w / (float)h); | |||
glViewport(0, 0, w, h); | |||
} | |||
} |
@@ -1,40 +0,0 @@ | |||
#include "builtins.h" | |||
namespace Cygnet { | |||
const GlShader &builtinTextureVertex() { | |||
static GlShader shader(GlShader::Type::VERTEX, R"( | |||
attribute vec4 position; | |||
attribute vec2 texCoord; | |||
varying vec2 v_texCoord; | |||
void main() { | |||
gl_Position = position; | |||
v_texCoord = texCoord; | |||
} | |||
)"); | |||
return shader; | |||
} | |||
const GlShader &builtinTextureFragment() { | |||
static GlShader shader(GlShader::Type::FRAGMENT, R"( | |||
precision mediump float; | |||
varying vec2 v_texCoord; | |||
uniform sampler2D tex; | |||
void main() { | |||
gl_FragColor = texture2D(tex, v_texCoord); | |||
} | |||
)"); | |||
return shader; | |||
} | |||
const GlShader &builtinWhiteFragment() { | |||
static GlShader shader(GlShader::Type::FRAGMENT, R"( | |||
precision mediump float; | |||
void main() { | |||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); | |||
} | |||
)"); | |||
return shader; | |||
} | |||
} |
@@ -1,36 +0,0 @@ | |||
#include "glutil.h" | |||
#include <SDL.h> | |||
#include <SDL_opengles2.h> | |||
#include <stdexcept> | |||
namespace Cygnet { | |||
const char *glErrorString(int err) { | |||
#define errcase(x) case x: return #x | |||
switch (err) { | |||
errcase(GL_NO_ERROR); | |||
errcase(GL_INVALID_ENUM); | |||
errcase(GL_INVALID_VALUE); | |||
errcase(GL_INVALID_OPERATION); | |||
errcase(GL_INVALID_FRAMEBUFFER_OPERATION); | |||
errcase(GL_OUT_OF_MEMORY); | |||
default: return "(unknown)"; | |||
} | |||
#undef errcase | |||
} | |||
void glCheck() { | |||
GLenum err = glGetError(); | |||
if (err != GL_NO_ERROR) { | |||
throw std::runtime_error(glErrorString(err)); | |||
} | |||
} | |||
void sdlAssert(bool val) { | |||
if (!val) { | |||
throw std::runtime_error(SDL_GetError()); | |||
} | |||
} | |||
} |