/*** 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 :) 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 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 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 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 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 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 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; }