spacebox/demo/cube/Cube.cpp

455 lines
16 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 and variable viewer, 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, log to stdout and file, variable
screen resolution, debug display, loading wheel animation, shadowed sprite,
separate update and draw, sprite movement cage, multiple windows, multiple
renderers, node children list, node animations list, copy constructor for all
base classes (esp. sprite, audio, pixels), private and public class members,
pixel class iterator, sprite movement history, input history, use seconds
instead of milliseconds, store a node's animations in list, frame object for
sprite class, inline short functions, add box2d to library, load in separate
thread and display progress, add anchor to box class, add comments to code,
generate documentation from comments, get resource function, automatically
update animations, add arguments list to animation call, queue multiple calls
to animation, print list of chunk and music decoders available, allow nodes
that aren't connected to root, add imagemagick to library, add curl to library,
fail if command line flag is unrecognized
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
***/
#include "Cube.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;
}
Mushroom::Mushroom(Node *parent) : Sprite(parent, "resource/shrooms")
{
set_frame_length(500);
std::cout << "mushroom constructor " << this << std::endl;
}
void Mushroom::update()
{
move_weighted({direction, 0});
int x = get_left();
glm::ivec2 resolution = get_display().window_size();
if (x > resolution.x or x < 0)
{
direction = -direction;
if (x > resolution.x)
{
move({resolution.x - x, 0});
}
else
{
move({-x, 0});
}
}
Sprite::update();
}
Cube::Cube()
{
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(&Cube::respond, this);
}
void Cube::load_sdl_context()
{
Game::load_sdl_context();
grass.load();
mushroom.load();
}
void Cube::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);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
std::vector<glm::vec3> vertices;
vertices.reserve(cube.size() + background_vertices.size());
vertices.insert(vertices.begin(), cube.begin(), cube.end());
vertices.insert(vertices.end(), background_vertices.begin(), background_vertices.end());
glm::ivec2 resolution = get_display().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 = sb::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, 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());
std::copy(cube_uv.begin(), cube_uv.end(), uv.begin());
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);
}
void Cube::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 Cube::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);
float rotation = .0005f * get_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_weighted({0, -speed});
}
if (right_active)
{
grass.move_weighted({speed, 0});
}
if (down_active)
{
grass.move_weighted({0, speed});
}
if (left_active)
{
grass.move_weighted({-speed, 0});
}
grass.update();
mushroom.update();
}
}
int main()
{
Cube cube = Cube();
cube.run();
cube.quit();
return 0;
}