doing stuff
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 11 Aug 2018 23:06:36 +0000 (02:06 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 11 Aug 2018 23:06:36 +0000 (02:06 +0300)
15 files changed:
Makefile
src/game.cc
src/gamescr.cc
src/goatkit/theme.cc
src/image.cc [new file with mode: 0644]
src/image.h [new file with mode: 0644]
src/menuscr.cc
src/opengl.c
src/opengl.h
src/screen.cc
src/screen.h
src/texture.cc [new file with mode: 0644]
src/texture.h [new file with mode: 0644]
src/uitheme.cc
tools/dlldepends [new file with mode: 0755]

index 4189eb2..27fd39b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,11 +12,16 @@ inc =
 
 CFLAGS = $(warn) $(dbg) $(opt) $(inc)
 CXXFLAGS = $(warn) $(dbg) $(opt) $(inc)
-LDFLAGS = $(libgl) $(syslibs)
+LDFLAGS = $(syslibs) $(libgl) -lgmath -limago
 
 sys := $(shell uname -s | sed 's/MINGW.*/mingw/')
 ifeq ($(sys), mingw)
+       obj = $(ccsrc:.cc=.w32.o) $(csrc:.c=.w32.o)
+       dep     = $(obj:.o=.d)
+       bin = game.exe
+
        libgl = -lopengl32 -lglu32 -lfreeglut -lglew32
+       syslibs = -lmingw32 -lwinmm
 else
        libgl = -lGL -lGLU -lglut -lGLEW
        syslibs = -ldl
@@ -33,6 +38,12 @@ $(bin): $(obj)
 %.d: %.cc
        @$(CPP) $(CXXFLAGS) $< -MM -MT $(@:.d=.o) >$@
 
+%.w32.o: %.c
+       $(CC) -o $@ $(CFLAGS) -c $<
+
+%.w32.o: %.cc
+       $(CC) -o $@ $(CXXFLAGS) -c $<
+
 .PHONY: clean
 clean:
        rm -f $(obj) $(bin)
@@ -40,3 +51,11 @@ clean:
 .PHONY: cleandep
 cleandep:
        rm -f $(dep)
+
+.PHONY: cross
+cross:
+       $(MAKE) CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ sys=mingw
+
+.PHONY: cross-clean
+cross-clean:
+       $(MAKE) CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ sys=mingw clean
index cf3f62a..230c619 100644 (file)
@@ -50,13 +50,12 @@ void game_keyboard(int key, bool pressed)
 {
        if(pressed) {
                switch(key) {
-               case 'q':
-               case 'Q':
-                       if(game_modkeys() & MODKEY_CTRL) {
-                               game_quit();
-                               return;
-                       }
-                       break;
+               case 17:
+                       /* for some inexplicable reason freeglut seems to produce key
+                        * 17 for ctrl-q on both X and windows.
+                        */
+                       game_quit();
+                       return;
 
                default:
                        break;
index 0ae1672..26afe42 100644 (file)
+#include <vector>
+#include <gmath/gmath.h>
 #include "game.h"
 #include "screen.h"
 #include "opengl.h"
+#include "texture.h"
+
+/* NOTES:
+ * - whistle hhgg music
+ * - colliding particles merge
+ * - select objects and center camera on them
+ */
+
+struct Particle {
+       float mass;
+       Vec2 pos;
+       Vec2 vel;
+};
+
+struct Emitter {
+       Vec2 pos;
+       float mass;
+       float rate, chunk;
+       float angle, spread;
+};
+
+
+#define SIM_DT         0.016
+
+#define GRID_SIZE      4096
+#define GRID_BITS      12
+#define GRID_X(idx)    (((idx) >> GRID_BITS) & (GRID_SIZE - 1))
+#define GRID_Y(idx)    ((idx) & (GRID_SIZE - 1))
+
+#define FIELD_SIZE     2048
+#define MIN_CAM_DIST   1.0f
+#define MAX_CAM_DIST   350.0f
+
+static int pos_to_grid(float x, float y);
+
+static float grid[GRID_SIZE * GRID_SIZE];
+static Particle grid_part[GRID_SIZE * GRID_SIZE];
+
+static std::vector<Emitter> emitters;
+
+static Texture *grid_tex;
+
+static float cam_theta;
+static float cam_dist = 100.0f;
+static Vec2 *targ_pos;
+static Mat4 view_matrix, proj_matrix;
+
 
 bool GameScreen::init()
 {
+       grid_tex = new Texture;
+       if(!grid_tex->load("data/purple_grid.png")) {
+               return false;
+       }
+       grid_tex->set_anisotropy(glcaps.max_aniso);
+
        return true;
 }
 
 void GameScreen::destroy()
 {
+       delete grid_tex;
+}
+
+static void simstep()
+{
 }
 
+static void update()
+{
+       static float interval;
+
+       interval += frame_dt;
+       if(interval >= SIM_DT) {
+               interval -= SIM_DT;
+               simstep();
+       }
+
+       // update projection matrix
+       proj_matrix.perspective(deg_to_rad(60.0f), win_aspect, 0.5, 5000.0);
+
+       // update view matrix
+       Vec3 targ;
+       if(targ_pos) {
+               targ.x = targ_pos->x;
+               targ.z = targ_pos->y;
+       }
+
+       float theta = -deg_to_rad(cam_theta);
+       Vec3 camdir = Vec3(sin(theta) * cam_dist, pow(cam_dist * 0.1, 2.0) + 0.5, cos(theta) * cam_dist);
+       Vec3 campos = targ + camdir;
+
+       view_matrix.inv_lookat(campos, targ, Vec3(0, 1, 0));
+}
 
 void GameScreen::draw()
 {
-       glClearColor(1, 0, 0, 1);
+       update();
+
+       glClearColor(0.01, 0.01, 0.01, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       glMatrixMode(GL_PROJECTION);
+       glLoadMatrixf(proj_matrix[0]);
+       glMatrixMode(GL_MODELVIEW);
+       glLoadMatrixf(view_matrix[0]);
+
+       glPushAttrib(GL_ENABLE_BIT);
+       glDisable(GL_LIGHTING);
+       glDisable(GL_CULL_FACE);
+
+       glEnable(GL_TEXTURE_2D);
+       bind_texture(grid_tex);
+
+       float maxu = FIELD_SIZE / 32.0f;
+       float maxv = FIELD_SIZE / 32.0f;
+       float hsz = FIELD_SIZE * 0.5f;
+
+       glBegin(GL_QUADS);
+       glColor3f(1, 1, 1);
+       glTexCoord2f(0, 0);
+       glVertex3f(-hsz, 0, -hsz);
+       glTexCoord2f(maxu, 0);
+       glVertex3f(hsz, 0, -hsz);
+       glTexCoord2f(maxu, maxv);
+       glVertex3f(hsz, 0, hsz);
+       glTexCoord2f(0, maxv);
+       glVertex3f(-hsz, 0, hsz);
+       glEnd();
+
+       glPopAttrib();
+}
+
+void GameScreen::reshape(int x, int y)
+{
 }
 
 
+
 void GameScreen::keyboard(int key, bool pressed)
 {
        if(pressed) {
@@ -33,14 +156,29 @@ void GameScreen::keyboard(int key, bool pressed)
        }
 }
 
+static int prev_x, prev_y;
+
 void GameScreen::mbutton(int bn, bool pressed, int x, int y)
 {
+       prev_x = x;
+       prev_y = y;
 }
 
 void GameScreen::mmotion(int x, int y)
 {
+       int dx = x - prev_x;
+       int dy = y - prev_y;
+       prev_x = x;
+       prev_y = y;
+
+       if(game_bnstate(2)) {
+               cam_theta += dx * 0.5;
+       }
 }
 
 void GameScreen::mwheel(int dir, int x, int y)
 {
+       cam_dist -= dir * cam_dist * 0.05f;
+       if(cam_dist <= MIN_CAM_DIST) cam_dist = MIN_CAM_DIST;
+       if(cam_dist > MAX_CAM_DIST) cam_dist = MAX_CAM_DIST;
 }
index 8f46615..65febbc 100644 (file)
@@ -27,6 +27,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #ifdef WIN32
 #include <windows.h>
 
+#define RTLD_LAZY      0
+
 static void *dlopen(const char *name, int flags);
 static void dlclose(void *so);
 static void *dlsym(void *so, const char *symbol);
@@ -289,7 +291,7 @@ static void *dlopen(const char *name, int flags)
 
 static void dlclose(void *so)
 {
-       FreeLibrary(so);
+       FreeLibrary((HMODULE)so);
 }
 
 static void *dlsym(void *so, const char *symbol)
@@ -297,6 +299,6 @@ static void *dlsym(void *so, const char *symbol)
        if(!so) {
                so = GetModuleHandle(0);
        }
-       return (void*)GetProcAddress(so, symbol);
+       return (void*)GetProcAddress((HMODULE)so, symbol);
 }
 #endif
diff --git a/src/image.cc b/src/image.cc
new file mode 100644 (file)
index 0000000..57817ca
--- /dev/null
@@ -0,0 +1,299 @@
+#include <string.h>
+
+#if defined(WIN32) || defined(__WIN32__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+#include "imago2.h"
+#include "image.h"
+
+static int pixel_elements(Image::Format fmt);
+static int elem_size(Image::Format fmt);
+static int pixel_size(Image::Format fmt);
+
+Image::Image()
+{
+       fmt = FMT_RGBA;
+       width = height = 0;
+       pixels = 0;
+}
+
+Image::~Image()
+{
+       delete [] (char*)pixels;
+}
+
+int Image::get_width() const
+{
+       return width;
+}
+
+int Image::get_height() const
+{
+       return height;
+}
+
+Image::Format Image::get_format() const
+{
+       return fmt;
+}
+
+bool Image::create(int x, int y, Format fmt)
+{
+       width = x;
+       height = y;
+       this->fmt = fmt;
+
+       try {
+               pixels = new char[x * y * pixel_size(fmt)];
+       }
+       catch(...) {
+               return false;
+       }
+       return true;
+}
+
+bool Image::set_pixels(int xsz, int ysz, void *pixels, Format fmt)
+{
+       if(!create(xsz, ysz, fmt)) {
+               return false;
+       }
+       memcpy(this->pixels, pixels, xsz * ysz * pixel_size(fmt));
+       return true;
+}
+
+bool Image::set_pixels(int xsz, int ysz, void *pixels, int scan_width, Format fmt)
+{
+       return set_pixels(xsz, ysz, pixels, 0, 0, scan_width, fmt);
+}
+
+bool Image::set_pixels(int xsz, int ysz, void *pixels, int x, int y, int scan_width, Format fmt)
+{
+       if(scan_width <= 0) {
+               scan_width = xsz;
+       }
+
+       if(!create(xsz, ysz, fmt)) {
+               return false;
+       }
+
+       int pixsz = pixel_size(fmt);
+
+       unsigned char *dest = (unsigned char*)this->pixels;
+       unsigned char *src = (unsigned char*)pixels + (y * scan_width + x) * pixsz;
+       for(int i=0; i<ysz; i++) {
+               memcpy(dest, src, xsz * pixsz);
+               dest += xsz * pixsz;
+               src += scan_width * pixsz;
+       }
+       return true;
+}
+
+void *Image::get_pixels() const
+{
+       return pixels;
+}
+
+void Image::flip_horizontal()
+{
+       int pixsz = pixel_size(fmt);
+
+       unsigned char *tmppix = (unsigned char*)alloca(pixsz);
+
+       unsigned char *scan = (unsigned char*)pixels;
+       for(int i=0; i<height; i++) {
+               unsigned char *dest = scan;
+               unsigned char *src = scan + (width - 1) * pixsz;
+
+               while(src > dest) {
+                       memcpy(tmppix, src, pixsz);
+                       memcpy(src, dest, pixsz);
+                       memcpy(dest, tmppix, pixsz);
+                       dest += pixsz;
+                       src -= pixsz;
+               }
+
+               scan += width * pixsz;
+       }
+}
+
+void Image::flip_vertical()
+{
+       int pixsz = pixel_size(fmt);
+
+       unsigned char *tmpscan = (unsigned char*)alloca(width * pixsz);
+
+       unsigned char *dest = (unsigned char*)pixels;
+       unsigned char *src = (unsigned char*)pixels + (height - 1) * width * pixsz;
+
+       while(src > dest) {
+               memcpy(tmpscan, src, width * pixsz);
+               memcpy(src, dest, width * pixsz);
+               memcpy(dest, tmpscan, width * pixsz);
+               dest += width * pixsz;
+               src -= width * pixsz;
+       }
+}
+
+void Image::rotate_180()
+{
+       flip_vertical();
+       flip_horizontal();
+}
+
+void Image::resize_half()
+{
+       int pixsz = pixel_size(fmt);
+       int newxsz = width / 2;
+       int newysz = height / 2;
+
+       if(!newxsz || !newysz) return;
+
+       unsigned char *newpix = new unsigned char[newxsz * newysz * pixsz];
+
+       unsigned char *sptr = (unsigned char*)pixels;
+       unsigned char *dptr = newpix;
+
+       for(int i=0; i<newysz; i++) {
+               if(i & 1) sptr += width * pixsz;
+               for(int j=0; j<newxsz; j++) {
+                       memcpy(dptr, sptr, pixsz);
+                       dptr += pixsz;
+                       sptr += pixsz * 2;
+               }
+       }
+
+       delete [] (char*)pixels;
+       pixels = newpix;
+       width = newxsz;
+       height = newysz;
+}
+
+bool Image::load(const char *fname)
+{
+       struct img_pixmap pixmap;
+
+       img_init(&pixmap);
+       if(img_load(&pixmap, fname) == -1) {
+               return false;
+       }
+
+       Format fmt;
+       switch(pixmap.fmt) {
+       case IMG_FMT_GREY8:
+               fmt = FMT_GREY;
+               break;
+       case IMG_FMT_RGB24:
+               fmt = FMT_RGB;
+               break;
+       case IMG_FMT_RGBA32:
+               fmt = FMT_RGBA;
+               break;
+       case IMG_FMT_GREYF:
+               fmt = FMT_GREY_FLOAT;
+               break;
+       case IMG_FMT_RGBF:
+               fmt = FMT_RGB_FLOAT;
+               break;
+       case IMG_FMT_RGBAF:
+               fmt = FMT_RGBA_FLOAT;
+               break;
+       default:
+               img_destroy(&pixmap);
+               return false;
+       }
+
+       if(!set_pixels(pixmap.width, pixmap.height, pixmap.pixels, fmt)) {
+               img_destroy(&pixmap);
+               return false;
+       }
+       img_destroy(&pixmap);
+       return true;
+}
+
+bool Image::save(const char *fname) const
+{
+       struct img_pixmap pixmap;
+
+       img_init(&pixmap);
+
+       switch(fmt) {
+       case FMT_GREY:
+               pixmap.fmt = IMG_FMT_GREY8;
+               break;
+       case FMT_GREY_FLOAT:
+               pixmap.fmt = IMG_FMT_GREYF;
+               break;
+       case FMT_RGB:
+               pixmap.fmt = IMG_FMT_RGB24;
+               break;
+       case FMT_RGB_FLOAT:
+               pixmap.fmt = IMG_FMT_RGBF;
+               break;
+       case FMT_RGBA:
+               pixmap.fmt = IMG_FMT_RGBA32;
+               break;
+       case FMT_RGBA_FLOAT:
+               pixmap.fmt = IMG_FMT_RGBAF;
+               break;
+       default:
+               return false;
+       }
+
+       pixmap.width = width;
+       pixmap.height = height;
+       pixmap.pixels = pixels;
+       pixmap.pixelsz = pixel_size(fmt);
+
+       if(img_save(&pixmap, fname) == -1) {
+               return false;
+       }
+       return true;
+}
+
+static int pixel_elements(Image::Format fmt)
+{
+       switch(fmt) {
+       case Image::FMT_GREY:
+       case Image::FMT_GREY_FLOAT:
+               return 1;
+
+       case Image::FMT_RGB:
+       case Image::FMT_RGB_FLOAT:
+               return 3;
+
+       case Image::FMT_RGBA:
+       case Image::FMT_RGBA_FLOAT:
+               return 4;
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int elem_size(Image::Format fmt)
+{
+       switch(fmt) {
+       case Image::FMT_GREY:
+       case Image::FMT_RGB:
+       case Image::FMT_RGBA:
+               return 1;
+
+       case Image::FMT_GREY_FLOAT:
+       case Image::FMT_RGB_FLOAT:
+       case Image::FMT_RGBA_FLOAT:
+               return sizeof(float);
+
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int pixel_size(Image::Format fmt)
+{
+       return elem_size(fmt) * pixel_elements(fmt);
+}
diff --git a/src/image.h b/src/image.h
new file mode 100644 (file)
index 0000000..1d16979
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef IMAGE_H_
+#define IMAGE_H_
+
+#include <string>
+
+class Image {
+public:
+       enum Format {
+               FMT_GREY,
+               FMT_RGB,
+               FMT_RGBA,
+               FMT_GREY_FLOAT,
+               FMT_RGB_FLOAT,
+               FMT_RGBA_FLOAT
+       };
+
+private:
+       Format fmt;
+       int width, height;
+       void *pixels;
+
+public:
+       std::string name;
+
+       Image();
+       ~Image();
+
+       int get_width() const;
+       int get_height() const;
+
+       Format get_format() const;
+
+       bool create(int x, int y, Format fmt = FMT_RGBA);
+       bool set_pixels(int xsz, int ysz, void *pixels, Format fmt = FMT_RGBA);
+       bool set_pixels(int xsz, int ysz, void *pixels, int scan_width, Format fmt = FMT_RGBA);
+       bool set_pixels(int xsz, int ysz, void *pixels, int x, int y, int scan_width = -1, Format fmt = FMT_RGBA);
+       void *get_pixels() const;
+
+       void flip_horizontal();
+       void flip_vertical();
+       void rotate_180();
+
+       void resize_half();
+
+       bool load(const char *fname);
+       bool save(const char *fname) const;
+};
+
+#endif // IMAGE_H_
index 7e910c4..00b0aa2 100644 (file)
@@ -34,14 +34,14 @@ bool MenuScreen::init()
        bn_start = new goatkit::Button;
        bn_start->set_position(xpos, ypos += vsep);
        bn_start->set_size(bnwidth, bnheight);
-       bn_start->set_text("Start");
+       bn_start->set_text("Don't Panic!");
        bn_start->set_callback(goatkit::EV_CLICK, bn_handler, (void*)BN_START);
        ui.add_widget(bn_start);
 
        bn_exit = new goatkit::Button;
        bn_exit->set_position(xpos, ypos += vsep);
        bn_exit->set_size(bnwidth, bnheight);
-       bn_exit->set_text("Exit");
+       bn_exit->set_text("Panic");
        bn_exit->set_callback(goatkit::EV_CLICK, bn_handler, (void*)BN_EXIT);
        ui.add_widget(bn_exit);
 
@@ -113,6 +113,18 @@ void MenuScreen::reshape(int x, int y)
 
 void MenuScreen::keyboard(int key, bool pressed)
 {
+       if(pressed) {
+               switch(key) {
+               case KEY_ESC:
+                       exit_pending = true;
+                       ui.hide();
+                       return;
+
+               default:
+                       break;
+               }
+       }
+
        ui.sysev_keyboard(key, pressed);
 }
 
index 7042514..5c3ff44 100644 (file)
@@ -15,6 +15,10 @@ int init_opengl(void)
 {
        glewInit();
 
+       if(GLEW_EXT_texture_filter_anisotropic) {
+               glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glcaps.max_aniso);
+       }
+
        glcaps.debug = GLEW_ARB_debug_output;
 
 #ifndef NDEBUG
index 80e4875..397cd38 100644 (file)
@@ -5,6 +5,7 @@
 
 struct GLCaps {
        int debug;      /* ARB_debug_output */
+       int max_aniso;
 };
 
 extern struct GLCaps glcaps;
index 6b9a274..1870796 100644 (file)
@@ -16,7 +16,8 @@ bool init_screens()
                return false;
        }
 
-       push_screen(scr_menu);
+       //push_screen(scr_menu);
+       push_screen(scr_game);
        return true;
 }
 
index c5422f9..6978b77 100644 (file)
@@ -55,6 +55,7 @@ public:
        void destroy();
 
        void draw();
+       void reshape(int x, int y);
 
        void keyboard(int key, bool pressed);
        void mbutton(int bn, bool pressed, int x, int y);
diff --git a/src/texture.cc b/src/texture.cc
new file mode 100644 (file)
index 0000000..d9e4f29
--- /dev/null
@@ -0,0 +1,486 @@
+#include <math.h>
+#include <assert.h>
+#include "texture.h"
+#include "image.h"
+#include "opengl.h"
+#include "imago2.h"
+
+static int glifmt_from_ifmt(unsigned int ifmt);
+static int glfmt_from_ifmt(unsigned int ifmt);
+static int gltype_from_ifmt(unsigned int ifmt);
+
+static int glifmt_from_imgfmt(Image::Format fmt);
+
+static unsigned int type_to_target(TextureType type);
+static TextureType target_to_type(unsigned int targ);
+
+static unsigned int cur_target[8] = {
+       GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
+       GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
+};
+
+static unsigned int cube_faces[] = {
+       GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+       GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+       GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+       GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+       GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+       GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
+};
+
+
+void bind_texture(Texture *tex, int tunit)
+{
+       if(tex) {
+               tex->bind(tunit);
+       } else {
+               glActiveTexture(GL_TEXTURE0 + tunit);
+               glBindTexture(cur_target[tunit], 0);
+               assert(glGetError() == GL_NO_ERROR);
+               glActiveTexture(GL_TEXTURE0);
+       }
+}
+
+Image *Texture::default_img;
+
+Texture::Texture()
+{
+       target = 0;
+       sz[0] = sz[1] = sz[2] = 0;
+       texfmt = 0;
+
+       img = 0;
+       glGenTextures(1, &id);
+}
+
+Texture::~Texture()
+{
+       if(id) {
+               glDeleteTextures(1, &id);
+       }
+       if(img) {
+               delete img;
+       }
+}
+
+void Texture::set_wrapping(unsigned int wrap)
+{
+       if(!target) {
+               return;
+       }
+
+       glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
+       glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
+       glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
+       glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap);
+}
+
+void Texture::set_filtering(unsigned int filt)
+{
+       unsigned int mag_filter;
+
+       if(!target) {
+               return;
+       }
+
+       switch(filt) {
+       case GL_LINEAR_MIPMAP_NEAREST:
+       case GL_LINEAR_MIPMAP_LINEAR:
+               mag_filter = GL_LINEAR;
+               break;
+
+       case GL_NEAREST_MIPMAP_NEAREST:
+       case GL_NEAREST_MIPMAP_LINEAR:
+               mag_filter = GL_NEAREST;
+               break;
+
+       default:
+               mag_filter = filt;
+       }
+
+       set_filtering(filt, mag_filter);
+}
+
+void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
+{
+       glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
+       glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
+       glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
+}
+
+void Texture::set_anisotropy(int aniso)
+{
+       if(aniso > glcaps.max_aniso) {
+               aniso = glcaps.max_aniso;
+       }
+
+       glBindTexture(target, id);
+       glTexParameteri(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso);
+}
+
+unsigned int Texture::get_format() const
+{
+       return texfmt;
+}
+
+int Texture::get_size(int dim) const
+{
+       if(dim < 0 || dim >= 3) {
+               return 0;
+       }
+       return sz[dim];
+}
+
+int Texture::get_width() const
+{
+       return sz[0];
+}
+
+int Texture::get_height() const
+{
+       return sz[1];
+}
+
+unsigned int Texture::get_id() const
+{
+       return id;
+}
+
+TextureType Texture::get_type() const
+{
+       return target_to_type(target);
+}
+
+void Texture::bind(int tex_unit) const
+{
+       glActiveTexture(GL_TEXTURE0 + tex_unit);
+       glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
+       glActiveTexture(GL_TEXTURE0);
+
+       cur_target[tex_unit] = target;
+}
+
+
+void Texture::create(int xsz, int ysz, TextureType textype, unsigned int ifmt)
+{
+       if(textype == TEX_CUBE && xsz != ysz) {
+               fprintf(stderr, "trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
+               return;
+       }
+
+       int fmt = glfmt_from_ifmt(ifmt);
+       int type = gltype_from_ifmt(ifmt);
+
+       target = type_to_target(textype);
+
+       glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
+       glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+       switch(textype) {
+       case TEX_2D:
+               glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
+               break;
+
+       case TEX_CUBE:
+               glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+               glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+               glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+               for(int i=0; i<6; i++) {
+                       glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
+               }
+               break;
+       }
+
+       sz[0] = xsz;
+       sz[1] = ysz;
+       texfmt = ifmt;
+}
+
+#define DEF_IMAGE_SIZE 64
+void Texture::create_default(TextureType type)
+{
+       if(!default_img) {
+               default_img = new Image;
+               default_img->create(DEF_IMAGE_SIZE, DEF_IMAGE_SIZE, Image::FMT_RGBA);
+
+               unsigned char *pixels = (unsigned char*)default_img->get_pixels();
+               for(int i=0; i<DEF_IMAGE_SIZE; i++) {
+                       for(int j=0; j<DEF_IMAGE_SIZE; j++) {
+                               bool chess = ((i >> 3) & 1) == ((j >> 3) & 1);
+                               pixels[0] = chess ? 255 : 32;
+                               pixels[1] = 64;
+                               pixels[2] = chess ? 32 : 255;
+                               pixels[3] = 255;
+                               pixels += 4;
+                       }
+               }
+       }
+
+       switch(type) {
+       case TEX_2D:
+               set_image(*default_img);
+               break;
+
+       case TEX_CUBE:
+               for(int i=0; i<6; i++) {
+                       set_image(*default_img, i);
+               }
+               break;
+       }
+}
+
+void Texture::set_image(const Image &img, int idx)
+{
+       if(idx >= 0 && idx < 6) {
+               set_image_cube(img, idx);
+       } else {
+               if(!set_image_cube(img)) {
+                       set_image_2d(img);
+               }
+       }
+}
+
+void Texture::set_image_2d(const Image &img)
+{
+       texfmt = glifmt_from_imgfmt(img.get_format());
+       unsigned int fmt = glfmt_from_ifmt(texfmt);
+       unsigned int type = gltype_from_ifmt(texfmt);
+
+       sz[0] = img.get_width();
+       sz[1] = img.get_height();
+
+       target = GL_TEXTURE_2D;
+       glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
+       glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+       glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+#ifdef __GLEW_H__
+       if(GLEW_SGIS_generate_mipmap) {
+               glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
+#endif
+               glTexImage2D(target, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
+#ifdef __GLEW_H__
+       } else {
+               gluBuild2DMipmaps(target, texfmt, sz[0], sz[1], fmt, type, img.get_pixels());
+       }
+#endif
+
+#ifdef GL_ES_VERSION_2_0
+       glGenerateMipmap(target);
+#endif
+}
+
+bool Texture::set_image_cube(const Image &img, int idx)
+{
+       unsigned int err;
+       if(idx < 0 || idx >= 6) {
+               return false;
+       }
+
+       texfmt = glifmt_from_imgfmt(img.get_format());
+       unsigned int fmt = glfmt_from_ifmt(texfmt);
+       unsigned int type = gltype_from_ifmt(texfmt);
+
+       sz[0] = img.get_width();
+       sz[1] = img.get_height();
+
+       target = GL_TEXTURE_CUBE_MAP;
+       glBindTexture(target, id);
+       if((err = glGetError()) == GL_INVALID_OPERATION) {
+               return false;   // probably not a cubemap
+       }
+       assert(err == GL_NO_ERROR);
+       glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+       glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+
+       glTexImage2D(cube_faces[idx], 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
+       return true;
+}
+
+bool Texture::set_image_cube(const Image &img)
+{
+       static const float one_third = 1.0 / 3.0;
+       static const float two_thirds = 2.0 / 3.0;
+       static const float hcross[2][6] = {
+               {0.5, 0.0, 0.25, 0.25, 0.25, 0.75}, {one_third, one_third, 0.0, two_thirds, one_third, one_third} };
+       static const float vcross[2][6] = {
+               {two_thirds, 0.0, one_third, one_third, one_third, one_third}, {0.25, 0.25, 0.0, 0.5, 0.25, 0.75} };
+       static const float hsix[2][6] = {
+               {0.0, 0.0, one_third, one_third, two_thirds, two_thirds}, {0.0, 0.5, 0.0, 0.5, 0.0, 0.5} };
+
+       int xsz = img.get_width();
+       int ysz = img.get_height();
+
+       if((xsz << 8) / 4 == (ysz << 8) / 3) {
+               // horizontal cross, assume the vertical bit is center-left
+               return set_cube_multi(img, hcross[0], hcross[1], xsz / 4);
+       }
+       if((xsz << 8) / 3 == (ysz << 8) / 4) {
+               // vertical cross, assume the horizontal bit is center-top (180-rotated image 5)
+               return set_cube_multi(img, vcross[0], vcross[1], ysz / 4, (1 << 5));
+       }
+       if((xsz << 8) / 3 == (ysz << 8) / 2) {
+               // horizontal sixpack
+               return set_cube_multi(img, hsix[0], hsix[1], ysz / 2);
+       }
+
+       return false;
+}
+
+
+bool Texture::load(const char *fname)
+{
+       Image img;
+       if(!img.load(fname)) {
+               fprintf(stderr, "failed to load 2D texture: %s\n", fname);
+               return false;
+       }
+       set_image(img);
+
+       printf("loaded 2D texture: %s\n", fname);
+       return true;
+}
+
+bool Texture::load_cube(const char *fname)
+{
+       Image img;
+       if(!img.load(fname)) {
+               return false;
+       }
+       return set_image_cube(img);
+}
+
+bool Texture::set_cube_multi(const Image &img, const float *xoffsets, const float *yoffsets, float sz,
+               unsigned int rotmask)
+{
+       for(int i=0; i<6; i++) {
+               Image face;
+
+               int xoffs = xoffsets[i] * img.get_width();
+               int yoffs = yoffsets[i] * img.get_height();
+
+               if(!face.set_pixels(sz, sz, img.get_pixels(), xoffs, yoffs, img.get_width(), img.get_format())) {
+                       return false;
+               }
+
+               if(rotmask & (1 << i)) {
+                       face.rotate_180();
+               }
+               set_image_cube(face, i);
+       }
+       return true;
+}
+
+static int glifmt_from_ifmt(unsigned int ifmt)
+{
+#ifdef GL_ES_VERSION_2_0
+       switch(ifmt) {
+       case GL_LUMINANCE16F_ARB:
+       case GL_LUMINANCE32F_ARB:
+               ifmt = GL_LUMINANCE;
+               break;
+
+       case GL_RGB16F:
+       case GL_RGB32F:
+               ifmt = GL_RGB;
+               break;
+
+       case GL_RGBA16F:
+       case GL_RGBA32F:
+               ifmt = GL_RGBA;
+               break;
+
+       default:
+               break;
+       }
+#endif
+       return ifmt;    // by default just pass it through...
+}
+
+static int glfmt_from_ifmt(unsigned int ifmt)
+{
+       switch(ifmt) {
+       case GL_LUMINANCE16F_ARB:
+       case GL_LUMINANCE32F_ARB:
+       case GL_SLUMINANCE:
+               return GL_LUMINANCE;
+
+       case GL_RGB16F:
+       case GL_RGB32F:
+       case GL_SRGB:
+               return GL_RGB;
+
+       case GL_RGBA16F:
+       case GL_RGBA32F:
+       case GL_SRGB_ALPHA:
+               return GL_RGBA;
+
+       default:
+               break;
+       }
+       return ifmt;
+}
+
+static int gltype_from_ifmt(unsigned int ifmt)
+{
+       switch(ifmt) {
+       case GL_RGB16F:
+       case GL_RGBA16F:
+       case GL_LUMINANCE16F_ARB:
+#ifdef GL_ES_VERSION_2_0
+               return GL_HALF_FLOAT_OES;
+#endif
+       case GL_RGB32F:
+       case GL_RGBA32F:
+       case GL_LUMINANCE32F_ARB:
+               return GL_FLOAT;
+
+       default:
+               break;
+       }
+       return GL_UNSIGNED_BYTE;
+}
+
+static int glifmt_from_imgfmt(Image::Format fmt)
+{
+       switch(fmt) {
+       case Image::FMT_GREY:
+               return GL_SLUMINANCE;
+       case Image::FMT_GREY_FLOAT:
+               return GL_LUMINANCE16F_ARB;
+       case Image::FMT_RGB:
+               return GL_SRGB;
+       case Image::FMT_RGB_FLOAT:
+               return GL_RGB16F;
+       case Image::FMT_RGBA:
+               return GL_SRGB_ALPHA;
+       case Image::FMT_RGBA_FLOAT:
+               return GL_RGBA16F;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static unsigned int type_to_target(TextureType type)
+{
+       return type == TEX_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+}
+
+static TextureType target_to_type(unsigned int targ)
+{
+       return targ == GL_TEXTURE_CUBE_MAP ? TEX_CUBE : TEX_2D;
+}
diff --git a/src/texture.h b/src/texture.h
new file mode 100644 (file)
index 0000000..5f74e98
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef TEXTURE_H_
+#define TEXTURE_H_
+
+#include "opengl.h"
+
+class Image;
+
+enum TextureType { TEX_2D, TEX_CUBE };
+
+class Texture {
+private:
+       unsigned int id;
+       unsigned int target;
+       unsigned int texfmt;
+       int sz[3];
+       Image *img;
+       static Image *default_img;
+
+       Texture(const Texture &tex) {}
+       Texture &operator =(const Texture &tex) { return *this; }
+
+       void set_image_2d(const Image &img);
+       bool set_image_cube(const Image &img, int idx);
+       bool set_image_cube(const Image &img);
+
+       bool load_cube(const char *fname);
+
+       /* for loading multiple cubemap faces from a single image */
+       bool set_cube_multi(const Image &img, const float *xoffsets, const float *yoffsets, float sz,
+               unsigned int rotmask = 0);
+
+public:
+       Texture();
+       ~Texture();
+
+       void set_wrapping(unsigned int wrap);
+       void set_filtering(unsigned int filt);
+       void set_filtering(unsigned int min_filt, unsigned int mag_filt);
+       void set_anisotropy(int aniso);
+
+       unsigned int get_format() const;
+
+       int get_size(int dim) const;
+       int get_width() const;
+       int get_height() const;
+
+       void create(int xsz, int ysz, TextureType type = TEX_2D, unsigned int ifmt = GL_RGBA);
+       void create_default(TextureType type = TEX_2D);
+       void set_image(const Image &img, int idx = -1);
+
+       bool load(const char *fname);
+
+       unsigned int get_id() const;
+       TextureType get_type() const;
+
+       void bind(int tex_unit = 0) const;
+};
+
+void bind_texture(Texture *tex, int tunit = 0);
+
+#endif // TEXTURE_H_
index 28c497c..9a98ef8 100644 (file)
@@ -45,12 +45,12 @@ static bool initialized;
 static std::map<std::string, DrawFunc> funcmap;
 
 /* theme colors */
-static float fgcol[] = {0.8, 0.6, 0.4, 1.0};
-static float fgcol_off[] = {0.65, 0.65, 0.6, 1.0};
+static float fgcol[] = {0.4, 0.5, 0.8, 1.0};
+static float fgcol_off[] = {0.5, 0.6, 0.65, 1.0};
 static float fgcol_inact[] = {0.4, 0.4, 0.4, 1.0};
-static float bgcol[] = {0.3, 0.3, 0.3, 1.0};
-static float bgcol_off[] = {0.3, 0.3, 0.3, 1.0};
-static float bgcol_inact[] = {0.3, 0.3, 0.3, 1.0};
+static float bgcol[] = {0.1, 0.1, 0.15, 1.0};
+static float bgcol_off[] = {0.1, 0.1, 0.15, 1.0};
+static float bgcol_inact[] = {0.1, 0.1, 0.15, 1.0};
 
 
 extern "C" goatkit::WidgetDrawFunc get_widget_func(const char *name)
diff --git a/tools/dlldepends b/tools/dlldepends
new file mode 100755 (executable)
index 0000000..7515d35
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/dash
+
+depends() {
+       dlls=$(strings $1 | grep '\.dll' | grep -v '\(USER32\|KERNEL32\|msvcrt\)')
+
+       gccver=$(i686-w64-mingw32-gcc -dumpversion | awk -F . '{ print $1 "." $2 }')
+
+       libpaths="/usr/i686-w64-mingw32/lib \
+       /usr/i686-w64-mingw32/bin \
+       /usr/lib/gcc/i686-w64-mingw32/$gccver-win32"
+
+       for i in $dlls; do
+               for path in $libpaths; do
+                       dllfile=$path/$i
+                       if [ -f $dllfile ]; then
+                               echo $dllfile
+                               if [ ! "$2" = noreq ]; then
+                                       depends $dllfile noreq
+                               fi
+                       fi
+               done
+       done
+}
+
+depends game.exe | sort | uniq