spacebox/demo/Demo.cpp

503 lines
17 KiB
C++

/***
reset, pause, auto reset, analog d-pad, gamepad config, any key, confirm exit
game, screen wipes, screen offset, screen scale, networking, post processing
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
*surf wizard*
*Exxiit* eXIt
***/
#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 = location.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;
}