spacebox/demo/Demo.cpp

511 lines
17 KiB
C++

/***
reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit
game, screen + sprite wipes, screen offset, screen scale, networking, post
processing, all objects deactivatable, all objects subscribed to events, all
objects resetable, wrapable & scrollable surface, separate window for
configuration console, text editor for config json, asset favoriting, audio
filters, enforce consistent angle orientation, floating point coordinates,
relative coordinates, relative lengths, relative sizes, delta time, specify
config parameters on command line, effects chain, asset dict with metadata,
move added sprite locations by offset when location is changed, gradients,
level select code input, logging, variable screen resolution, debug display,
loading wheel animation, shadowed sprite
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
***/
#include "Demo.hpp"
char* file_to_buf(const char *path)
{
FILE *fp;
long length;
char *buf;
fp = fopen(path, "rb");
if (not fp)
{
return NULL;
}
fseek(fp, 0, SEEK_END);
length = ftell(fp);
buf = (char*) malloc(length + 1);
fseek(fp, 0, SEEK_SET);
fread(buf, length, 1, fp);
fclose(fp);
buf[length] = 0;
return buf;
}
GLuint load_shader(const char* path, GLenum type)
{
char *source = file_to_buf(path);
GLuint shader = glCreateShader(type);
int is_compiled, max_length;
glShaderSource(shader, 1, (const GLchar**) &source, 0);
glCompileShader(shader);
glGetShaderiv(shader, GL_COMPILE_STATUS, &is_compiled);
if(is_compiled == 0)
{
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
char *log = (char *) malloc(max_length);
glGetShaderInfoLog(shader, max_length, &max_length, log);
fprintf(stderr, "%s -- shader compilation failed %s\n", path, log);
free(log);
return -1;
}
return shader;
}
int link_shader(GLuint program)
{
glLinkProgram(program);
int is_linked, max_length;
glGetProgramiv(program, GL_LINK_STATUS, (int *) &is_linked);
if(is_linked == 0)
{
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
char *log = (char *) malloc(max_length);
glGetProgramInfoLog(program, max_length, &max_length, log);
fprintf(stderr, "shader program %i linking failed %s\n", program, log);
free(log);
return -1;
}
return 0;
}
GLuint get_gl_texture_from_surface(SDL_Surface *surface, GLint mipmap_filter, bool invert = false)
{
GLuint id;
glCreateTextures(GL_TEXTURE_2D, 1, &id);
glBindTexture(GL_TEXTURE_2D, id);
GLenum format;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
format = invert ? GL_RGBA : GL_BGRA;
#else
format = invert ? GL_BGRA : GL_RGBA;
#endif
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, format,
GL_UNSIGNED_BYTE, surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mipmap_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmap_filter);
return id;
}
SDL_Surface* get_framerate_indicator_surface(int frame_count)
{
TTF_Font* font = TTF_OpenFont("resource/SourceCodePro-Regular.otf", 14);
std::string padded = sfw::pad(frame_count, 2);
SDL_Surface* shaded = TTF_RenderText_Shaded(
font, padded.c_str(), {0, 0, 0}, {255, 255, 255});
SDL_Surface* converted = SDL_ConvertSurfaceFormat(
shaded, SDL_PIXELFORMAT_ARGB8888, 0);
SDL_Surface* flipped = zoomSurface(converted, 1, -1, SMOOTHING_OFF);
SDL_FreeSurface(shaded);
SDL_FreeSurface(converted);
if (not flipped)
{
fprintf(stderr, "Could not create text %s\n", SDL_GetError());
}
TTF_CloseFont(font);
return flipped;
}
void set_framerate_indicator(int frame_count, GLuint id)
{
SDL_Surface* message = get_framerate_indicator_surface(frame_count);
glBindTexture(GL_TEXTURE_2D, id);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, message->w, message->h, GL_BGRA,
GL_UNSIGNED_BYTE, message->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
SDL_FreeSurface(message);
}
Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms")
{
set_frame_length(500);
std::cout << "mushroom constructor " << this << std::endl;
}
void Mushroom::update()
{
move(direction);
int x = box.get_x();
glm::ivec2 resolution = get_display().get_window_size();
if (x > resolution.x or x < 0)
{
direction = -direction;
if (x > resolution.x)
{
move(resolution.x - x);
}
else
{
move(-x);
}
}
Sprite::update();
}
Demo::Demo()
{
Mix_Music *music = Mix_LoadMUS("resource/Field.mp3");
// Mix_Music *music = Mix_LoadMUS("/home/frank/WATERMELON-clean.mp3");
Mix_PlayMusic(music, -1);
load_gl_context();
delegate.subscribe(&Demo::respond, this);
}
void Demo::load_sdl_context()
{
Game::load_sdl_context();
grass.load();
mushroom.load();
}
void Demo::load_gl_context()
{
Game::load_gl_context();
grass.unload();
mushroom.unload();
/*
v0-v1-v2 (front)
v2-v3-v0
v0-v3-v4 (right)
v4-v5-v0
v0-v5-v6 (top)
v6-v1-v0
v1-v6-v7 (left)
v7-v2-v1
v7-v4-v3 (bottom)
v3-v2-v7
v4-v7-v6 (back)
v6-v5-v4
*/
std::array<glm::vec3, 36> cube = {
{
{1, 1, 1}, {-1, 1, 1}, {-1,-1, 1},
{-1,-1, 1}, {1,-1, 1}, {1, 1, 1},
{1, 1, 1}, {1,-1, 1}, {1,-1,-1},
{1,-1,-1}, {1, 1,-1}, {1, 1, 1},
{1, 1, 1}, {1, 1,-1}, {-1, 1,-1},
{-1, 1,-1}, {-1, 1, 1}, {1, 1, 1},
{-1, 1, 1}, {-1, 1,-1}, {-1,-1,-1},
{-1,-1,-1}, {-1,-1, 1}, {-1, 1, 1},
{-1,-1,-1}, {1,-1,-1}, {1,-1, 1},
{1,-1, 1}, {-1,-1, 1}, {-1,-1,-1},
{1,-1,-1}, {-1,-1,-1}, {-1, 1,-1},
{-1, 1,-1}, {1, 1,-1}, {1,-1,-1}
}};
std::array<glm::vec3, 6> background_vertices = {
{
{-1, 1, 0}, {1, 1, 0}, {-1, -1, 0},
{1, 1, 0}, {1, -1, 0}, {-1, -1, 0}
}};
GLfloat background_colors[40][3] = {
{.2, .6, .8}, {.2, .6, .8}, {1, 1, 0},
{.2, .6, .8}, {1, 1, 0}, {1, 1, 0}
};
GLuint background_colors_buffer;
glGenBuffers(1, &background_colors_buffer);
std::array<glm::vec3, 6> framerate_indicator_vertices = {
{
{.9, 1, 0}, {1, 1, 0}, {.9, .9, 0},
{1, 1, 0}, {1, .9, 0}, {.9, .9, 0}
}};
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
std::vector<glm::vec3> vertices;
vertices.reserve(cube.size() + background_vertices.size() + framerate_indicator_vertices.size());
vertices.insert(vertices.begin(), cube.begin(), cube.end());
vertices.insert(vertices.end(), background_vertices.begin(), background_vertices.end());
vertices.insert(vertices.end(), framerate_indicator_vertices.begin(),
framerate_indicator_vertices.end());
glm::ivec2 resolution = get_display().get_window_size();
projection = glm::perspective(
glm::radians(45.0f), resolution.x / (float) resolution.y, 0.1f,
100.0f);
view = glm::lookAt(
glm::vec3(4, 3, 3), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
SDL_Surface* surface = zoomSurface(
rotateSurface90Degrees(IMG_Load("resource/tile.png"), 2), -1, 1, SMOOTHING_OFF);
SDL_Log("tile.png bytes per pixel %i", surface->format->BytesPerPixel);
space_texture_id = get_gl_texture_from_surface(surface, GL_LINEAR, true);
SDL_FreeSurface(surface);
// std::vector<fs::path> paths = sfw::glob("/home/frank/projects/public/games/buddi/local/face03/[0-9]+\\-.+\\.png");
// for (fs::path path : paths)
// {
// surface = zoomSurface(rotateSurface90Degrees(IMG_Load(path.c_str()), 2), -1, 1, SMOOTHING_OFF);
// SDL_Log("loading %s", path.c_str());
// face_ids.push_back(get_gl_texture_from_surface(surface, GL_LINEAR));
// SDL_FreeSurface(surface);
// }
std::array<glm::vec2, 6> framerate_indicator_uv = {
{
{0, 1}, {1, 1}, {0, 0},
{1, 1}, {1, 0}, {0, 0}
}};
std::array<glm::vec2, 36> cube_uv = {
{
{1, 1}, {0, 1}, {0, 0},
{0, 0}, {1, 0}, {1, 1},
{0, 1}, {0, 0}, {1, 0},
{1, 0}, {1, 1}, {0, 1},
{0, 1}, {0, 0}, {1, 0},
{1, 0}, {1, 1}, {0, 1},
{1, 1}, {0, 1}, {0, 0},
{0, 0}, {1, 0}, {1, 1},
{0, 0}, {1, 0}, {1, 1},
{1, 1}, {0, 1}, {0, 0},
{0, 0}, {1, 0}, {1, 1},
{1, 1}, {0, 1}, {0, 0}
}};
std::vector<glm::vec2> uv;
uv.reserve(cube_uv.size() + background_vertices.size() + framerate_indicator_uv.size());
std::copy(cube_uv.begin(), cube_uv.end(), uv.begin());
std::copy(framerate_indicator_uv.begin(), framerate_indicator_uv.end(),
uv.begin() + cube_uv.size() + background_vertices.size());
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
unsigned char fake_texture_color[4] = {255, 255, 255, 255};
glCreateTextures(GL_TEXTURE_2D, 1, &fake_texture_id);
glBindTexture(GL_TEXTURE_2D, fake_texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
fake_texture_color);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat) * 3, &vertices.front(),
GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, uv.capacity() * sizeof(GLfloat) * 2, &uv.front(), GL_STATIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, background_colors_buffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat) * 3, 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER,
(cube.size()) * sizeof(GLfloat) * 3,
background_vertices.size() * sizeof(GLfloat) * 3, background_colors);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(2);
GLuint vertex_shader = load_shader("shaders/triangle.vert", GL_VERTEX_SHADER);
GLuint fragment_shader = load_shader("shaders/triangle.frag", GL_FRAGMENT_SHADER);
GLuint flat_shader = load_shader("shaders/flat.vert", GL_VERTEX_SHADER);
world_program = glCreateProgram();
glAttachShader(world_program, vertex_shader);
glAttachShader(world_program, fragment_shader);
glBindAttribLocation(world_program, 0, "in_Position");
glBindAttribLocation(world_program, 1, "vertexUV");
glBindAttribLocation(world_program, 2, "in_Color");
glBindAttribLocation(world_program, 3, "pos");
link_shader(world_program);
flat_program = glCreateProgram();
glAttachShader(flat_program, flat_shader);
glAttachShader(flat_program, fragment_shader);
glBindAttribLocation(flat_program, 0, "in_Position");
glBindAttribLocation(flat_program, 1, "vertexUV");
glBindAttribLocation(flat_program, 2, "in_Color");
glBindAttribLocation(flat_program, 3, "pos");
link_shader(flat_program);
mvp_id = glGetUniformLocation(world_program, "MVP");
// GLuint sampler_uniform_id = glGetUniformLocation(world_program, "myTextureSampler");
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, space_texture_id);
// glUniform1i(sampler_uniform_id, 0);
glDepthFunc(GL_LESS);
frame_count_timestamp = SDL_GetTicks();
SDL_Surface* fps_surface = get_framerate_indicator_surface(frame_count);
framerate_texture_id = get_gl_texture_from_surface(fps_surface, GL_LINEAR);
SDL_FreeSurface(fps_surface);
}
void Demo::respond(SDL_Event& event)
{
if (delegate.compare(event, "context"))
{
if (is_gl_context)
{
load_sdl_context();
}
else
{
load_gl_context();
}
}
else if (delegate.compare(event, "play-sound"))
{
Mix_Chunk* music = Mix_LoadWAV("resource/Ag.ogg");
Mix_PlayChannel(-1, music, 0);
}
else if (delegate.compare(event, "fullscreen"))
{
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)
{
SDL_SetWindowFullscreen(window, 0);
}
else
{
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
}
}
}
void Demo::update()
{
// while (SDL_PollEvent(&event))
// {
// if (event.type == SDL_KEYDOWN)
// {
// if (SDL_GetModState() & KMOD_CTRL)
// {
// if (event.key.keysym.sym == SDLK_f)
// {
// show_framerate = not show_framerate;
// }
// else if (event.key.keysym.sym == SDLK_UP)
// {
// set_framerate(framerate + 1);
// }
// else if (event.key.keysym.sym == SDLK_DOWN)
// {
// set_framerate(framerate - 1);
// }
// }
// else if (event.key.keysym.sym == SDLK_UP)
// {
// up_active = true;
// }
// else if (event.key.keysym.sym == SDLK_RIGHT)
// {
// right_active = true;
// }
// else if (event.key.keysym.sym == SDLK_DOWN)
// {
// down_active = true;
// }
// else if (event.key.keysym.sym == SDLK_LEFT)
// {
// left_active = true;
// }
// }
// else if (event.type == SDL_KEYUP)
// {
// if (event.key.keysym.sym == SDLK_UP)
// {
// up_active = false;
// }
// else if (event.key.keysym.sym == SDLK_RIGHT)
// {
// right_active = false;
// }
// else if (event.key.keysym.sym == SDLK_DOWN)
// {
// down_active = false;
// }
// else if (event.key.keysym.sym == SDLK_LEFT)
// {
// left_active = false;
// }
// }
// }
if (is_gl_context)
{
// glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
// glBufferData(GL_ARRAY_BUFFER, 8 * sizeof(GLfloat), diamond, GL_STATIC_DRAW);
// glColorMask(false, false, false, true);
// glClearColor(.7, .7, .5, 1);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glUseProgram(flat_program);
glUniform1f(glGetUniformLocation(flat_program, "r"), mvp[0][0]);
glBindTexture(GL_TEXTURE_2D, fake_texture_id);
glDisableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 36, 6);
if (show_framerate)
{
glBindTexture(GL_TEXTURE_2D, framerate_texture_id);
glDisableVertexAttribArray(2);
glEnableVertexAttribArray(1);
glVertexAttrib3f(2, 1, 1, 1);
glDrawArrays(GL_TRIANGLES, 42, 6);
}
// printf("%s\n", glm::to_string(model).c_str());
float rotation = .0005f * frame_length;
model = glm::rotate(model, rotation, glm::vec3(0.0f, 1.0f, 0.0f));
mvp = projection * view * model;
glEnable(GL_DEPTH_TEST);
glUseProgram(world_program);
glUniformMatrix4fv(mvp_id, 1, GL_FALSE, &mvp[0][0]);
glEnableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glVertexAttrib3f(2, 1, 1, 1);
// for (int ii = 0; ii < 6; ii++)
// {
// glBindTexture(GL_TEXTURE_2D, face_ids[ii]);
// glDrawArrays(GL_TRIANGLES, ii * 6, 6);
// }
glBindTexture(GL_TEXTURE_2D, space_texture_id);
glDrawArrays(GL_TRIANGLES, 0, 36);
//glFlush();
SDL_GL_SwapWindow(window);
// if (amount_rotated < 3.14f * 2)
// {
// recorder.capture_screen();
// }
amount_rotated += rotation;
}
else
{
SDL_SetRenderDrawColor(renderer, 0x0f, 0x4f, 0x8f, 0xff);
SDL_RenderClear(renderer);
roundedBoxColor(renderer, 300, 200, 500, 300, 10, 0x8f8fdfff);
aacircleColor(renderer, 300, 200, 30, 0xffef3fff);
int speed = 2;
if (up_active)
{
grass.move(0, -speed);
}
if (right_active)
{
grass.move(speed);
}
if (down_active)
{
grass.move(0, speed);
}
if (left_active)
{
grass.move(-speed, 0);
}
grass.update();
mushroom.update();
SDL_RenderPresent(renderer);
}
frame_count++;
if (ticks - frame_count_timestamp >= 1000)
{
frame_count_timestamp = ticks;
if (is_gl_context and show_framerate)
{
set_framerate_indicator(frame_count, framerate_texture_id);
}
frame_count = 0;
}
}
int main(int argc, char *argv[])
{
Demo demo = Demo();
demo.run();
demo.quit();
return 0;
}