attribute vec4 attr_vertex, attr_color;
attribute vec2 attr_texcoord;
+uniform mat4 matrix_modelview_projection;
+
varying vec4 color;
varying vec2 texcoord;
void main()
{
- gl_Position = attr_vertex;
+ gl_Position = matrix_modelview_projection * attr_vertex;
texcoord = attr_texcoord;
color = attr_color;
}
#include <stdio.h>
+#include <stdlib.h>
#include <stdint.h>
#include "demo.h"
#include "opengl.h"
#include "sanegl.h"
#include "assman.h"
#include "cmesh.h"
+#include "music.h"
+static void draw_texquad(float x, float y, float w, float h);
+static int piece_hit(int x, int y);
static void gen_default_textures(void);
static unsigned int sdr_foo;
static unsigned int tex_logo;
+static unsigned int tex_bg, tex_piece;
+static int bg_width, bg_height;
+static float bg_aspect;
+static int piece_width, piece_height;
+static float vis_width, vis_height;
+static float xoffs, yoffs;
+static float xpos, ypos;
+static int dragging;
+static int prev_mx, prev_my;
+static int xtarg, ytarg;
+static int inplace;
int demo_init(void)
{
return -1;
}
+ if(init_music() == -1) {
+ return -1;
+ }
+
/* global "debug" shader which just visualizes normals */
if(!(sdr_dbg = get_sdrprog("sdr/dbg.v.glsl", "sdr/dbg.p.glsl"))) {
return -1;
gl_end();
swap_buffers();
- glEnable(GL_DEPTH_TEST);
+ if(!(tex_bg = get_tex2d("data/bunny_bg.jpg"))) {
+ return -1;
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ bg_width = 2048;
+ bg_height = 1360;
+ bg_aspect = (float)bg_width / (float)bg_height;
+
+ if(!(tex_piece = get_tex2d("data/bunny.png"))) {
+ return -1;
+ }
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ piece_width = piece_height = 512;
+
+ xtarg = 933;
+ ytarg = 443;
+
+ glDisable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
return 0;
}
void demo_cleanup(void)
{
+ destroy_music();
destroy_assman();
glDeleteTextures(1, &deftex_white);
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glBindTexture(GL_TEXTURE_2D, tex_logo);
+ gl_matrix_mode(GL_MODELVIEW);
+ gl_load_identity();
+ gl_translatef(xoffs, yoffs, 0);
+
+ glBindTexture(GL_TEXTURE_2D, tex_bg);
glUseProgram(sdr_foo);
- gl_begin(GL_QUADS);
+
gl_color3f(1, 1, 1);
+ draw_texquad(0, 0, bg_width, bg_height);
+
+ gl_load_identity();
+ gl_translatef(xpos, vis_height - ypos - piece_height, 0);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glBindTexture(GL_TEXTURE_2D, tex_piece);
+ if(!inplace) {
+ gl_color4f(0, 0, 0, 0.65);
+ draw_texquad(10, -15, piece_width, piece_height);
+ }
+ gl_color3f(1, 1, 1);
+ draw_texquad(0, 0, piece_width, piece_height);
+
+ glDisable(GL_BLEND);
+}
+
+static void draw_texquad(float x, float y, float w, float h)
+{
+ gl_begin(GL_QUADS);
gl_texcoord2f(0, 1);
- gl_vertex2f(-1, -1);
+ gl_vertex2f(x, y);
gl_texcoord2f(1, 1);
- gl_vertex2f(1, -1);
+ gl_vertex2f(x + w, 0);
gl_texcoord2f(1, 0);
- gl_vertex2f(1, 1);
+ gl_vertex2f(x + w, y + h);
gl_texcoord2f(0, 0);
- gl_vertex2f(-1, 1);
+ gl_vertex2f(x, y + h);
gl_end();
}
win_width = x;
win_height = y;
win_aspect = (float)x / (float)y;
+
+ gl_matrix_mode(GL_PROJECTION);
+ gl_load_identity();
+ if(bg_aspect >= win_aspect) {
+ vis_width = bg_width;
+ vis_height = bg_width / win_aspect;
+ xoffs = 0;
+ yoffs = (vis_height - bg_height) * 0.5f;
+ } else {
+ vis_width = bg_height * win_aspect;
+ vis_height = bg_height;
+ xoffs = (bg_height * win_aspect - bg_width) * 0.5f;
+ yoffs = 0;
+ }
+ gl_ortho(0, vis_width, 0, vis_height, -1, 1);
}
void demo_keyboard(int key, int pressed)
{
+ if(!pressed) return;
+
+ switch(key) {
+ case ' ':
+ xpos = xtarg + xoffs;
+ ypos = ytarg + yoffs;
+ break;
+ }
+}
+
+static void scr_to_vis(int *xp, int *yp)
+{
+ float x = (float)*xp;
+ float y = (float)*yp;
+ *xp = x / (float)win_width * (float)vis_width;
+ *yp = y / (float)win_height * (float)vis_height;
}
void demo_mouse(int bn, int pressed, int x, int y)
{
+ if(pressed) {
+ scr_to_vis(&x, &y);
+ if(piece_hit(x, y)) {
+ dragging = 1;
+ prev_mx = x;
+ prev_my = y;
+ inplace = 0;
+ }
+ } else {
+ if(dragging) {
+ dragging = 0;
+
+ if(fabs(xpos - (xtarg + xoffs)) < 20 && fabs(ypos - (ytarg + yoffs)) < 20) {
+ xpos = xtarg + xoffs;
+ ypos = ytarg + yoffs;
+ inplace = 1;
+ play_music();
+ }
+ }
+ }
}
void demo_motion(int x, int y)
{
+ int dx, dy;
+
+ scr_to_vis(&x, &y);
+
+ dx = x - prev_mx;
+ dy = y - prev_my;
+ prev_mx = x;
+ prev_my = y;
+
+ if(!dragging || !(dx | dy)) {
+ return;
+ }
+
+ xpos += dx;
+ ypos += dy;
+
+ if(xpos < 0) xpos = 0;
+ if(ypos < 0) ypos = 0;
+ if(xpos + piece_width > vis_width) xpos = vis_width - piece_width;
+ if(ypos + piece_height > vis_height) ypos = vis_height - piece_height;
+}
+
+static int piece_hit(int x, int y)
+{
+ if(x < xpos) return 0;
+ if(x >= xpos + piece_width) return 0;
+ if(y < ypos) return 0;
+ if(y >= ypos + piece_height) return 0;
+ return 1;
}
static void gen_default_textures(void)
--- /dev/null
+#include <stdio.h>
+#include <sys/stat.h>
+#include "music.h"
+#include "assfile.h"
+#include "miniaudio/miniaudio.h"
+
+static const char *fmtname(ma_format fmt);
+static ma_result vopen(ma_vfs *vfs, const char *path, ma_uint32 mode, ma_vfs_file *fret);
+static ma_result vclose(ma_vfs *vfs, ma_vfs_file fp);
+static ma_result vread(ma_vfs *vfs, ma_vfs_file fp, void *dest, size_t sz, size_t *numread);
+static ma_result vseek(ma_vfs *vfs, ma_vfs_file fp, ma_int64 offs, ma_seek_origin from);
+static ma_result vtell(ma_vfs *vfs, ma_vfs_file fp, ma_int64 *pos);
+static ma_result vinfo(ma_vfs *vfs, ma_vfs_file fp, ma_file_info *inf);
+
+static int init_done;
+static ma_engine engine;
+static ma_sound sound;
+static ma_resource_manager resman;
+static ma_uint32 sample_rate;
+static float volume;
+
+static ma_vfs_callbacks vfs = {
+ vopen, 0,
+ vclose,
+ vread, 0,
+ vseek,
+ vtell,
+ vinfo
+};
+
+int init_music(void)
+{
+ ma_engine_config engcfg;
+ ma_resource_manager_config rescfg;
+ unsigned int flags;
+ ma_format fmt;
+ ma_uint32 nchan;
+
+ rescfg = ma_resource_manager_config_init();
+ rescfg.pVFS = &vfs;
+ if(ma_resource_manager_init(&rescfg, &resman) != 0) {
+ fprintf(stderr, "failed to initialize miniaudio resource manager\n");
+ return -1;
+ }
+
+ engcfg = ma_engine_config_init();
+ engcfg.pResourceManager = &resman;
+
+ if(ma_engine_init(&engcfg, &engine) != 0) {
+ fprintf(stderr, "failed to initialize miniaudio engine\n");
+ return -1;
+ }
+
+ flags = MA_SOUND_FLAG_STREAM;
+ if(ma_sound_init_from_file(&engine, "data/woodclick.wav", flags, 0, 0, &sound) != 0) {
+ fprintf(stderr, "failed to load music\n");
+ return -1;
+ }
+ ma_sound_get_data_format(&sound, &fmt, &nchan, &sample_rate, 0, 0);
+ printf("loaded sound: %s %u.%03u khz, %u channels\n", fmtname(fmt),
+ (unsigned int)sample_rate / 1000, (unsigned int)sample_rate % 1000,
+ (unsigned int)nchan);
+
+ init_done = 1;
+ volume = 1.0f;
+ return 0;
+}
+
+void destroy_music(void)
+{
+ if(init_done) {
+ ma_sound_stop(&sound);
+ ma_sound_uninit(&sound);
+ ma_engine_uninit(&engine);
+ }
+ init_done = 0;
+}
+
+void play_music(void)
+{
+ if(init_done) {
+ ma_sound_start(&sound);
+ }
+}
+
+void stop_music(void)
+{
+ if(init_done) {
+ ma_sound_stop(&sound);
+ }
+}
+
+void seek_music(long tm)
+{
+ ma_uint64 frm;
+
+ if(init_done) {
+ if(tm < 0) tm = 0;
+ frm = (ma_uint64)tm * (ma_uint64)sample_rate / 1000llu;
+ ma_sound_seek_to_pcm_frame(&sound, frm);
+ }
+}
+
+void set_music_volume(float vol)
+{
+ if(init_done) {
+ volume = vol;
+ ma_engine_set_volume(&engine, vol);
+ }
+}
+
+
+static const char *fmtname(ma_format fmt)
+{
+ switch(fmt) {
+ case ma_format_u8: return "8 bit";
+ case ma_format_s16: return "16 bit";
+ case ma_format_s24: return "24 bit";
+ case ma_format_s32: return "32 bit";
+ case ma_format_f32: return "float";
+ default:
+ return "unknown";
+ }
+}
+
+static ma_result vopen(ma_vfs *vfs, const char *path, ma_uint32 mode, ma_vfs_file *fret)
+{
+ ass_file *fp;
+
+ if(mode != MA_OPEN_MODE_READ) return -1;
+
+ if(!(fp = ass_fopen(path, "rb"))) {
+ return -1;
+ }
+ *fret = fp;
+ return 0;
+}
+
+static ma_result vclose(ma_vfs *vfs, ma_vfs_file fp)
+{
+ ass_fclose(fp);
+ return 0;
+}
+
+static ma_result vread(ma_vfs *vfs, ma_vfs_file fp, void *dest, size_t sz, size_t *numread)
+{
+ size_t res;
+
+ res = ass_fread(dest, 1, sz, fp);
+ if(numread) *numread = res;
+
+ if(res != sz) {
+ if(res == 0) return MA_AT_END;
+ }
+ return MA_SUCCESS;
+}
+
+static ma_result vseek(ma_vfs *vfs, ma_vfs_file fp, ma_int64 offs, ma_seek_origin org)
+{
+ int from;
+ switch(org) {
+ case ma_seek_origin_start:
+ from = SEEK_SET;
+ break;
+ case ma_seek_origin_current:
+ from = SEEK_CUR;
+ break;
+ case ma_seek_origin_end:
+ from = SEEK_END;
+ break;
+ }
+ return ass_fseek(fp, offs, from) == -1 ? -1 : 0;
+}
+
+static ma_result vtell(ma_vfs *vfs, ma_vfs_file fp, ma_int64 *pos)
+{
+ *pos = ass_ftell(fp);
+ return 0;
+}
+
+static ma_result vinfo(ma_vfs *vfs, ma_vfs_file fp, ma_file_info *inf)
+{
+ int fd;
+ struct stat st;
+
+#ifdef _MSC_VER
+ fd = _fileno(fp);
+#else
+ fd = fileno(fp);
+#endif
+
+ if(fstat(fd, &st) != 0) {
+ return MA_ERROR;
+ }
+ inf->sizeInBytes = st.st_size;
+ return MA_SUCCESS;
+}
--- /dev/null
+#ifndef MUSIC_H_
+#define MUSIC_H_
+
+int init_music(void);
+void destroy_music(void);
+
+void play_music(void);
+void stop_music(void);
+void seek_music(long tm);
+
+void set_music_volume(float vol);
+
+#endif /* MUSIC_H_ */