From 47996000e230af15c2131d671d5bb5d20ca8fae1 Mon Sep 17 00:00:00 2001 From: darkrose Date: Sat, 19 Mar 2016 17:13:04 +1000 Subject: [PATCH] graphics updates --- Makefile.sources | 2 +- README | 3 +- inc/common.h | 17 ++- inc/graphics.h | 146 +++++++++++++++++-- inc/list.h | 1 + inc/wm.h | 10 +- src/client/events.c | 66 ++------- src/client/events_w32.c | 2 +- src/client/events_x11.c | 19 +-- src/core/config_default.c | 22 +-- src/graphics/camera.c | 10 +- src/graphics/font_ttf.c | 8 +- src/graphics/framebuffer.c | 149 +++++++++++++++++++ src/graphics/lighting.c | 93 ++++++++++++ src/graphics/material.c | 222 ++++++++++++++++++++-------- src/graphics/object.c | 41 +++++- src/graphics/opengl.c | 30 +++- src/graphics/particles.c | 272 ++++++++++++++++++++++++++++++++++ src/graphics/render.c | 68 ++++++++- src/graphics/render3d.c | 345 +++++++++++++++++++++++++++++--------------- src/graphics/shader.c | 90 +++++++++++- src/graphics/texture.c | 161 ++++++++++++++++----- src/graphics/wm_x11.c | 4 +- src/lib/list.c | 21 +++ src/server/dummy_commands.c | 8 + 25 files changed, 1462 insertions(+), 348 deletions(-) create mode 100644 src/graphics/framebuffer.c create mode 100644 src/graphics/particles.c diff --git a/Makefile.sources b/Makefile.sources index 9b8b0fd..e3569ff 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -22,7 +22,7 @@ OBJS_CONTENT=$(CONTENTDIR)/content.o $(CONTENTDIR)/content_block.o $(CONTENTDIR) OBJS_MAP= -OBJS_GRAPHICS=$(GLDIR)/camera.o $(GLDIR)/font.o $(GLDIR)/font_ttf.o $(GLDIR)/image.o $(GLDIR)/image_bmp.o $(GLDIR)/image_png.o $(GLDIR)/image_tga.o $(GLDIR)/lighting.o $(GLDIR)/material.o $(GLDIR)/mesh.o $(GLDIR)/object.o $(GLDIR)/opengl.o $(GLDIR)/render.o $(GLDIR)/render2d.o $(GLDIR)/render3d.o $(GLDIR)/shader.o $(GLDIR)/textbuffer.o $(GLDIR)/texture.o $(GLDIR)/wm.o $(GLDIR)/wm_x11.o $(GLDIR)/wm_w32.o +OBJS_GRAPHICS=$(GLDIR)/camera.o $(GLDIR)/font.o $(GLDIR)/font_ttf.o $(GLDIR)/framebuffer.o $(GLDIR)/image.o $(GLDIR)/image_bmp.o $(GLDIR)/image_png.o $(GLDIR)/image_tga.o $(GLDIR)/lighting.o $(GLDIR)/material.o $(GLDIR)/mesh.o $(GLDIR)/object.o $(GLDIR)/opengl.o $(GLDIR)/particles.o $(GLDIR)/render.o $(GLDIR)/render2d.o $(GLDIR)/render3d.o $(GLDIR)/shader.o $(GLDIR)/textbuffer.o $(GLDIR)/texture.o $(GLDIR)/wm.o $(GLDIR)/wm_x11.o $(GLDIR)/wm_w32.o OBJS_UI=$(UIDIR)/ui.o diff --git a/README b/README index 976915d..a595ea1 100644 --- a/README +++ b/README @@ -25,9 +25,8 @@ common.h - includes some 3D maths, logging, and config functions, as well as som SOME TODO: collision.c is waiting on content*.c/h for getting block data -config.c is waiting on command parsing log.c is waiting on ui and in-game console -Makefile.mingw-cross/.bsd/other-platform need writting +Makefile.mingw-cross/other-platform need writting crypto needs sha1 content can probably start going in, very little graphics support in content features at the moment though help system in command system needs implementing, also help function should list all commands diff --git a/inc/common.h b/inc/common.h index 2482dba..fa38f8e 100644 --- a/inc/common.h +++ b/inc/common.h @@ -63,6 +63,16 @@ typedef struct colour_s { } colour_t; #endif +#ifndef _HAVE_V4_TYPE +#define _HAVE_V4_TYPE +typedef struct v4_s { + float w; + float x; + float y; + float z; +} __attribute__((packed)) v4_t; +#endif + #ifndef _HAVE_V3_TYPE #define _HAVE_V3_TYPE typedef struct v3_s { @@ -119,12 +129,7 @@ typedef struct pos_s { #ifndef _HAVE_QUATERNION_TYPE #define _HAVE_QUATERNION_TYPE -typedef struct quaternion_s { - float w; - float x; - float y; - float z; -} __attribute__((packed)) quaternion_t; +typedef v4_t quaternion_t; #endif #ifndef _HAVE_MATRIX_TYPE diff --git a/inc/graphics.h b/inc/graphics.h index ebaf6cb..2cd4674 100644 --- a/inc/graphics.h +++ b/inc/graphics.h @@ -80,9 +80,10 @@ typedef struct texture_s { struct texture_s *prev; struct texture_s *next; GLuint glid; + GLenum type; int state; int id; - char name[100]; + char name[256]; int w; int h; GLfloat xf; @@ -97,9 +98,9 @@ typedef struct material_s { struct material_s *prev; struct material_s *next; int id; - char name[100]; + char name[256]; uint32_t options; - texture_t *tex; + array_t textures; float shininess; float reflectivity; float bumpiness; @@ -132,7 +133,6 @@ typedef struct mesh_s { array_t *m; /* weight map */ GLenum mode; int option; - float radius; aabox_t bounds; } mesh_t; #endif @@ -216,9 +216,7 @@ typedef struct object_s { v3_t pos; v3_t rot; v3_t scale; - float radius; aabox_t bounds; - array_t *abounds; anim_state_t anim; } object_t; #endif @@ -234,6 +232,18 @@ typedef struct object2d_s { } object2d_t; #endif +#ifndef _HAVE_MAPOBJ_TYPE +#define _HAVE_MAPOBJ_TYPE +typedef struct mapobj_s { + struct mapobj_s *prev; + struct mapobj_s *next; + mesh_t *mesh; + v3_t pos; + v3_t fpos; + aabox_t bounds; +} mapobj_t; +#endif + #ifndef _HAVE_SHADER_TYPE #define _HAVE_SHADER_TYPE typedef struct shader_s { @@ -312,6 +322,76 @@ typedef struct textbuffer_s { } textbuffer_t; #endif +#ifndef _HAVE_LIGHT_TYPE +#define _HAVE_LIGHT_TYPE +typedef struct light_s { + struct light_s *prev; + struct light_s *next; + int id; + v3_t pos; + colour_t colour; + v3_t att; + float d; +} light_t; +#endif + +#ifndef _HAVE_FBO_BUFFER_TYPE +#define _HAVE_FBO_BUFFER_TYPE +typedef union fbo_buffer_s { + GLuint glid; + texture_t *texture; +} fbo_buffer_t; +#endif + +#ifndef _HAVE_FRAMEBUFFER_TYPE +#define _HAVE_FRAMEBUFFER_TYPE +typedef struct framebuffer_s { + struct framebuffer_s *prev; + struct framebuffer_s *next; + int id; + int w; + int h; + GLuint glid; + fbo_buffer_t colour; + fbo_buffer_t depth; +} framebuffer_t; +#endif + +#ifndef _HAVE_PARTICLE_TYPE +#define _HAVE_PARTICLE_TYPE +typedef struct particle_s { + struct particle_s *prev; + struct particle_s *next; + v3_t pos; + v3_t speed; + float gravity; + float life; + float rotation; + float scale; + float dtime; +} particle_t; +#endif + +#ifndef _HAVE_PARTICLE_EMITTER_TYPE +#define _HAVE_PARTICLE_EMITTER_TYPE +typedef struct particle_emitter_s { + struct particle_emitter_s *prev; + struct particle_emitter_s *next; + int id; + material_t *mat; + v3_t pos; + v3_t dir; + int count; + int frames; + float gravity; + float life; + float particle_life; + float dtime; + float scale; + particle_t *particles; +} particle_emitter_t; +#endif + /* defined in image.c */ image_t *image_load(char* type, char* file); image_t *image_load_frommem(file_t *f); @@ -342,20 +422,21 @@ int image_load_tga(file_t *f, image_t *p); int image_save_tga(image_t *p, char* file); /* defined in material.c */ +material_t *mat_find(char* name); material_t *mat_create(void); void mat_free(material_t *mat); material_t *mat_from_tex(texture_t *tex); material_t *mat_from_pixels(image_t *p); -material_t *mat_update_pixels(material_t *mat, image_t *p); material_t *mat_from_image(char* type, char* file); +material_t *mat_from_box(char* front, char* back, char* left, char* right, char* top, char* bottom); +int mat_add_image(material_t *mat, char* type, char* file); +int mat_add_tex(material_t *mat, texture_t *tex); material_t *mat_from_colour(colour_t *c); int mat_bind_with_opts(GLuint tex, uint32_t options); void mat_use(material_t *mat, shader_t *shader); void mat_shininess(material_t *mat, float shininess, float reflectivity); void mat_bumpiness(material_t *mat, float bumpiness); void mat_name(material_t *mat, char* name); -void mat_tex(material_t *mat, texture_t *tex); -void mat_tex_file(material_t *mat, char* type, char* file); uint32_t mat_options(material_t *mat, uint32_t opt); /* defined in texture.c */ @@ -363,6 +444,7 @@ int tex_generate(texture_t *tex); texture_t *tex_create(void); void tex_free(texture_t *tex); texture_t *tex_from_image(char* type, char* file); +texture_t *tex_from_box(char* front, char* back, char* left, char* right, char* top, char* bottom); texture_t *tex_from_pixels(image_t *px); texture_t *tex_update_pixels(texture_t *tex, image_t *px); texture_t *tex_from_rgba(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a); @@ -376,6 +458,8 @@ int opengl_has_mipmap(void); int opengl_has_particles(void); int opengl_particles_max(void); int opengl_has_psdf(void); +int opengl_get_shadow_passes(void); +int opengl_get_shadow_size(void); char* opengl_error_string(GLenum e); /* defined in mesh.c */ @@ -403,8 +487,11 @@ void object_set_skeleton(object_t *o, int skel); void object_set_frame(object_t *o, int frame); int object_advance_frame(object_t *o, float dtime); void object_calc_normals(object_t *o); +void object_calc_bounds(object_t *o); /* defined in render.c */ +void render_set_projection_matrix(matrix_t *m); +matrix_t *render_get_projection_matrix(void); void render_pre(void); void render_post(void); float client_dtime(void); @@ -421,10 +508,12 @@ object_t *render3d_object_find(int id); void render3d_object_free(object_t *o); object_t *render3d_object_create(void); object_t *render3d_model(model_t *mod, v3_t *pos); -object_t *render3d_mesh(mesh_t *m, v3_t *pos); object_t *render3d_cube(float scale, v3_t *pos, material_t *mat); -void render3d_set_projection_matrix(void); -void render3d(void); +void render3d(camera_t *cam, v4_t *plane); + +/* defined in render_map.c */ +mapobj_t *render_map_chunk(mesh_t *m, v3_t *pos, aabox_t *bounds); +void render_map(camera_t *cam, v4_t *plane); /* defined in shader.c */ shader_t *shader_create(char* name); @@ -434,7 +523,10 @@ int shader_uniform_int(shader_t *s, char* name, int value); int shader_uniform_float(shader_t *s, char* name, float value); int shader_uniform_v2(shader_t *s, char* name, v2_t *value); int shader_uniform_v3(shader_t *s, char* name, v3_t *value); +int shader_uniform_v4(shader_t *s, char* name, v4_t *value); +int shader_uniform_colour(shader_t *s, char* name, colour_t *value); int shader_uniform_matrix(shader_t *s, char* name, matrix_t *value); +int shader_uniform_light(shader_t *s, int slot, light_t *light); int shader_enable(shader_t *s); int shader_disable(shader_t *s); @@ -458,4 +550,34 @@ int textbuffer_addstr(textbuffer_t *t, char* str); int textbuffer_addchar(textbuffer_t *t, uint32_t ch); int textbuffer_get_dimensions(textbuffer_t *t, int sizes[2]); +/* defined in model.c */ +model_t *model_create(void); +void model_free(model_t *mdl); +model_t *model_load(char* file); + +/* defined in model_obj.c */ +model_t *model_load_obj(file_t *f); + +/* defined in lighting.c */ +int light_add(colour_t *colour, v3_t *pos, v3_t *att); +void light_remove(int id); +void light_bind_near(shader_t *s, v3_t *pos); + +/* defined in water.c */ +void water_init(void); +void water_add(float x, float z); +void water_prerender(camera_t *cam); +void water_render(void); + +/* defined in framebuffer.c */ +framebuffer_t *fbo_create(int w, int h, uint8_t c_texture, uint8_t d_texture); +void fbo_free(framebuffer_t *f); +framebuffer_t *fbo_get(int id); +void fbo_use(framebuffer_t *f); +void fbo_unbind_all(void); + +/* defined in particles.c */ +particle_emitter_t *particles_emit(v3_t *pos, v3_t *dir, float life, float particle_life, float gravity, float scale, int frames, int count, material_t *mat); +void particles_render(void); + #endif diff --git a/inc/list.h b/inc/list.h index 8dd9af0..e75ad33 100644 --- a/inc/list.h +++ b/inc/list.h @@ -20,5 +20,6 @@ void *list_pop(void *list); void *list_pull(void *list); void *list_insert(void *list, void *el, void *n); void *list_insert_cmp(void *list, void *el, int (*list_cmp)(void *e1, void *e2)); +void *list_resort_cmp(void *list, int (*list_cmp)(void *e1, void* e2)); #endif diff --git a/inc/wm.h b/inc/wm.h index c9b10eb..c0e70c5 100644 --- a/inc/wm.h +++ b/inc/wm.h @@ -214,7 +214,7 @@ void wm_ungrab(void); void wm_title(char* title); /* defined in camera.c */ -void camera_view_matrix(matrix_t *mat); +void camera_view_matrix(matrix_t *mat, camera_t *cam); camera_t *camera_get(void); void camera_set_pos(v3_t *p); void camera_set_yaw(GLfloat yaw); @@ -232,11 +232,7 @@ void events_exit(void); void events_set_mousegrab(uint8_t g); uint8_t events_get_mousegrab(void); void events_get_mouse(int p[2]); -void event_set_bind(char* name, char* value); -void event_set_func(char* name, void (*func)(event_t *e)); -void event_set_r_func(char* name, void (*func)(event_t *e)); -void event_set_a_func(char* name, void (*func)(event_t *e)); -void event_set_com(char* name, char* com); +void events_set_mouse(int x, int y); void event_remove(char* name); void event_create(char* name, char* bind, char* com, void (*func)(event_t *e), void (*r_func)(event_t *e), void (*a_func)(event_t *e)); void events_trigger_active(void); @@ -262,6 +258,8 @@ int opengl_particles_setter(char* value); int opengl_particles_max_setter(char* value); int opengl_bumpmap_setter(char* value); int opengl_psdf_setter(char* value); +int opengl_shadowpass_setter(char* value); +int opengl_shadowsize_setter(char* value); /* defined in events.c and dummy.c */ void events_save(file_t *f); diff --git a/src/client/events.c b/src/client/events.c index 554f13d..d2c92c8 100644 --- a/src/client/events.c +++ b/src/client/events.c @@ -134,11 +134,19 @@ static void event_deactivate_sym(sym_t *s) } } +/* TODO: this shouldn't be */ +static void event_exit(event_t *e) +{ + client_state(VLSTATE_EXIT); +} + /* initialise configured events */ int events_init() { array_init(&event_data.syms,ARRAY_TYPE_PTR); - event_create("forward","w","forward",NULL,NULL,NULL); + event_create("forward","w","forwart",NULL,NULL,NULL); + + event_create("exit","esc","exit",event_exit,NULL,NULL); return 0; } @@ -181,6 +189,11 @@ void events_get_mouse(int p[2]) p[0] = event_data.mouse.pos[0]; p[1] = event_data.mouse.pos[1]; } +void events_set_mouse(int x, int y) +{ + event_data.mouse.pos[0] = x; + event_data.mouse.pos[1] = y; +} /* set the key bind for an event */ void event_set_bind(char* name, char* value) @@ -249,48 +262,6 @@ int event_bind(array_t *a) return 0; } -/* set the action function for an event */ -void event_set_func(char* name, void (*func)(event_t *e)) -{ - action_t *a = event_get_action(name); - if (!a) - return; - - a->func = func; -} - -/* set the release function for an event */ -void event_set_r_func(char* name, void (*func)(event_t *e)) -{ - action_t *a = event_get_action(name); - if (!a) - return; - - a->r_func = func; -} - -/* set the active function for an event */ -void event_set_a_func(char* name, void (*func)(event_t *e)) -{ - action_t *a = event_get_action(name); - if (!a) - return; - - a->a_func = func; -} - -/* set the command for an event */ -void event_set_com(char* name, char* com) -{ - action_t *a = event_get_action(name); - if (!a) - return; - - if (a->com) - free(a->com); - a->com = strdup(com); -} - /* remove an event */ void event_remove(char* name) { @@ -408,10 +379,10 @@ void events_handle(event_t *e) }else if (e->type == EVENT_KEY_UP || e->type == EVENT_BUTTON_UP) { event_deactivate_sym(&e->sym); }else if (e->type == EVENT_MOUSE_MOTION) { - e->rx = e->x-event_data.mouse.pos[0]; - e->ry = e->y-event_data.mouse.pos[0]; event_data.mouse.rel[0] = e->rx; event_data.mouse.rel[1] = e->ry; + event_data.mouse.pos[0] = e->x; + event_data.mouse.pos[1] = e->y; } b.sym.type = e->sym.type; @@ -451,9 +422,4 @@ void events_handle(event_t *e) } a = a->next; } - - if (e->type == EVENT_MOUSE_MOTION) { - event_data.mouse.pos[0] = e->x; - event_data.mouse.pos[1] = e->y; - } } diff --git a/src/client/events_w32.c b/src/client/events_w32.c index b5ab480..3384960 100644 --- a/src/client/events_w32.c +++ b/src/client/events_w32.c @@ -366,7 +366,7 @@ void events_main() MSG msg; while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if (msg.message == WM_QUIT) { - client_state(VLSTATE_EXIT); + client_state(TUSTATE_EXIT); }else{ TranslateMessage(&msg); DispatchMessage(&msg); diff --git a/src/client/events_x11.c b/src/client/events_x11.c index a32dfe1..45b1b00 100644 --- a/src/client/events_x11.c +++ b/src/client/events_x11.c @@ -361,6 +361,9 @@ void events_main() events_get_mouse(rm); e.rx = e.x-rm[0]; e.ry = e.y-rm[1]; + e.sym.type = SYM_TYPE_MOUSE; + e.sym.sym = MOUSE_MOTION; + events_set_mouse(e.x,e.y); if (e.rx > -100 && e.rx < 100 && e.ry > -100 && e.ry < 100) { events_handle(&e); if (events_get_mousegrab()) { @@ -375,13 +378,6 @@ void events_main() e.type = EVENT_KEY_DOWN; xevent_to_sym(&e.sym,&event); xkey_to_char(&e.sym.ch,&event); - if (e.sym.sym) { - char buffs[6]; - char buffc[6]; - utf8_fromutf32(buffs,6,e.sym.sym); - utf8_fromutf32(buffc,6,e.sym.ch); - vlprintf(CN_INFO,"P %u %u '%s' '%s'\n",e.sym.sym,e.sym.ch,buffs,buffc); - } if (e.sym.sym) events_handle(&e); break; @@ -397,15 +393,8 @@ void events_main() break; } } - e.type = EVENT_KEY_DOWN; + e.type = EVENT_KEY_UP; xevent_to_sym(&e.sym,&event); - if (e.sym.sym) { - char buffs[6]; - char buffc[6]; - utf8_fromutf32(buffs,6,e.sym.sym); - utf8_fromutf32(buffc,6,e.sym.ch); - vlprintf(CN_INFO,"R %u %u '%s' '%s'\n",e.sym.sym,e.sym.ch,buffs,buffc); - } if (e.sym.sym) events_handle(&e); break; diff --git a/src/core/config_default.c b/src/core/config_default.c index 2a1ddc5..c0d2d46 100644 --- a/src/core/config_default.c +++ b/src/core/config_default.c @@ -23,12 +23,12 @@ void config_default_init() { - config_set_default("log.min_level","1",log_minlevel_setter); - config_set_default("log.max_level","5",log_maxlevel_setter); - config_set_default("log.system.min_level","4",log_sminlevel_setter); - config_set_default("log.system.max_level","5",log_smaxlevel_setter); - config_set_default("log.console.min_level","4",log_cminlevel_setter); - config_set_default("log.console.max_level","5",log_cmaxlevel_setter); + config_set_default("log.min_level","error",log_minlevel_setter); + config_set_default("log.max_level","info",log_maxlevel_setter); + config_set_default("log.system.min_level","chat",log_sminlevel_setter); + config_set_default("log.system.max_level","info",log_smaxlevel_setter); + config_set_default("log.console.min_level","chat",log_cminlevel_setter); + config_set_default("log.console.max_level","info",log_cmaxlevel_setter); config_set_default("path.log",NULL,log_file_setter); config_set_default("path.data.custom",NULL,path_custom_setter); @@ -41,14 +41,16 @@ void config_default_init() config_set_default("wm.fullscreen","false",wm_fullscreen_setter); config_set_default("wm.capture_format","png",NULL); - config_set_default("gl.anisotropic","false",opengl_anisotropic_setter); - config_set_default("gl.bilinear","false",opengl_bilinear_setter); - config_set_default("gl.trilinear","false",opengl_trilinear_setter); - config_set_default("gl.mipmaps","false",opengl_mipmap_setter); + config_set_default("gl.anisotropic","true",opengl_anisotropic_setter); + config_set_default("gl.bilinear","true",opengl_bilinear_setter); + config_set_default("gl.trilinear","true",opengl_trilinear_setter); + config_set_default("gl.mipmaps","true",opengl_mipmap_setter); config_set_default("gl.particles.enabled","true",opengl_particles_setter); config_set_default("gl.particles.max","1000",opengl_particles_max_setter); config_set_default("gl.bumpmaps","true",opengl_bumpmap_setter); config_set_default("gl.psdf","true",opengl_psdf_setter); + config_set_default("gl.shadows.passes","1",opengl_shadowpass_setter); + config_set_default("gl.shadows.resolution","512",opengl_shadowsize_setter); config_set_default("ui.font.unifont","false",NULL); config_set_default("ui.scale","1.0",ui_scale_setter); diff --git a/src/graphics/camera.c b/src/graphics/camera.c index 85ef38f..f1db5de 100644 --- a/src/graphics/camera.c +++ b/src/graphics/camera.c @@ -30,12 +30,14 @@ static camera_t camera = { }; /* move to the camera position */ -void camera_view_matrix(matrix_t *mat) +void camera_view_matrix(matrix_t *mat, camera_t *cam) { + if (!cam) + cam = &camera; matrix_init(mat); - matrix_rotate_deg_x(mat,camera.pitch); - matrix_rotate_deg_y(mat,-camera.yaw); - matrix_translate(mat,-camera.x, -camera.y, -camera.z); + matrix_translate(mat,-cam->x, -cam->y, -cam->z); + matrix_rotate_deg_y(mat,-cam->yaw); + matrix_rotate_deg_x(mat,cam->pitch); } /* get the camera data */ diff --git a/src/graphics/font_ttf.c b/src/graphics/font_ttf.c index e2fb490..6b09b76 100644 --- a/src/graphics/font_ttf.c +++ b/src/graphics/font_ttf.c @@ -100,8 +100,6 @@ static int font_ttf_gen_fontpage(font_t *f, uint32_t i) uint32_t sy; uint32_t ax; uint32_t ay; - int b = 0; - int t = 0; int m = 0; int j; int k; @@ -196,10 +194,10 @@ static int font_ttf_gen_fontpage(font_t *f, uint32_t i) l = (ax+(ay*s)); p->pixels[l] = 255; l++; - if (k >= bitmap_glyph->bitmap.width || j >= bitmap_glyph->bitmap.rows) { + if (k >= gw || j >= gh) { p->pixels[l] = 0; }else{ - p->pixels[l] = bitmap_glyph->bitmap.buffer[k + bitmap_glyph->bitmap.width*j]; + p->pixels[l] = bitmap_glyph->bitmap.buffer[k+(gw*j)]; } } } @@ -215,8 +213,6 @@ static int font_ttf_gen_fontpage(font_t *f, uint32_t i) glGenTextures(1,&p->glid); glBindTexture(GL_TEXTURE_2D, p->glid); - b = opengl_has_bilinear(); - t = opengl_has_trilinear(); m = opengl_has_mipmap(); /* draw the pixels to the texture */ diff --git a/src/graphics/framebuffer.c b/src/graphics/framebuffer.c new file mode 100644 index 0000000..ec13e66 --- /dev/null +++ b/src/graphics/framebuffer.c @@ -0,0 +1,149 @@ +/************************************************************************ +* framebuffer.c +* voxelands - 3d voxel world sandbox game +* Copyright (C) Lisa 'darkrose' Milne 2016 +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +************************************************************************/ + +#include "common.h" +#include "graphics.h" +#include "list.h" + +static struct { + framebuffer_t *buffers; + int ids; +} fbo_data = { + NULL, + 0 +}; + +/* create a texture attachment for a fbo */ +static int fbo_create_texture(int w, int h, fbo_buffer_t *b, uint8_t d) +{ + texture_t *t; + + t = tex_create(); + + glGenTextures(1,&t->glid); + glBindTexture(GL_TEXTURE_2D, t->glid); + if (d) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, w, h, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + }else{ + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + if (d) { + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, t->glid, 0); + }else{ + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, t->glid, 0); + } + + t->state = 1; + + b->texture = t; + + return 0; +} + +/* create a buffer attachment for a fbo */ +static int fbo_create_buffer(int w, int h, fbo_buffer_t *b) +{ + glGenRenderbuffers(1,&b->glid); + + glBindRenderbuffer(GL_RENDERBUFFER, b->glid); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, b->glid); + + return 0; +} + +/* create a frame buffer object of width and height, with colour and depth buffers optionally bound to textures */ +framebuffer_t *fbo_create(int w, int h, uint8_t c_texture, uint8_t d_texture) +{ + framebuffer_t *f; + + f = malloc(sizeof(framebuffer_t)); + if (!f) + return NULL; + + f->depth.glid = 0; + f->colour.glid = 0; + f->id = ++fbo_data.ids; + f->w = w; + f->h = h; + + glGenFramebuffers(1,&f->glid); + + glBindFramebuffer(GL_FRAMEBUFFER, f->glid); + + if (c_texture) { + glDrawBuffer(GL_COLOR_ATTACHMENT0); + fbo_create_texture(w,h,&f->colour,0); + }else{ + glDrawBuffer(GL_NONE); + } + + if (d_texture) { + fbo_create_texture(w,h,&f->depth,1); + }else{ + fbo_create_buffer(w,h,&f->depth); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + fbo_data.buffers = list_append(&fbo_data.buffers,f); + + return f; +} + +/* free a framebuffer */ +void fbo_free(framebuffer_t *f) +{ + /* TODO: this */ +} + +/* get a framebuffer by id */ +framebuffer_t *fbo_get(int id) +{ + framebuffer_t *f = fbo_data.buffers; + + while (f) { + if (f->id == id) + return f; + f = f->next; + } + + return NULL; +} + +/* use/bind a framebuffer */ +void fbo_use(framebuffer_t *f) +{ + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, f->glid); + glViewport(0, 0, f->w, f->h); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); +} + +/* unbind framebuffers */ +void fbo_unbind_all() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, wm_data.size.width, wm_data.size.height); +} diff --git a/src/graphics/lighting.c b/src/graphics/lighting.c index f9a2246..7bfaabe 100644 --- a/src/graphics/lighting.c +++ b/src/graphics/lighting.c @@ -19,4 +19,97 @@ #include "common.h" #include "graphics.h" +#include "array.h" +#include "list.h" +static struct { + int ids; + array_t lights; +} light_data = { + -1 +}; + +/* comparison functions: + * return 0 to insert + * return 1 to insert later + * return -1 to not insert at all + */ +static int light_insert_cmp(void *e1, void *e2) +{ + light_t *l1; + light_t *l2; + + l1 = e1; + l2 = e2; + + if (l1->d < l2->d) + return 0; + return 1; +} + +int light_add(colour_t *colour, v3_t *pos, v3_t *att) +{ + light_t *l; + if (light_data.ids < 0) + array_init(&light_data.lights,ARRAY_TYPE_PTR); + + l = malloc(sizeof(light_t)); + if (!l) + return -1; + + l->pos.x = pos->x; + l->pos.y = pos->y; + l->pos.z = pos->z; + + l->colour.r = colour->r; + l->colour.g = colour->g; + l->colour.b = colour->b; + l->colour.a = colour->a; + + if (att) { + l->att.x = att->x; + l->att.y = att->y; + l->att.z = att->z; + }else{ + l->att.x = 1.0; + l->att.y = 0.0; + l->att.z = 0.0; + } + + l->id = ++light_data.ids; + + array_push_ptr(&light_data.lights,l); + + return -1; +} + +void light_remove(int id) +{ +} + +void light_bind_near(shader_t *s, v3_t *pos) +{ + int i; + light_t *l; + light_t *nearby = NULL; + + if (light_data.ids < 0) + return; + + for (i=0; id = math_distance(pos,&l->pos); + nearby = list_insert_cmp(&nearby,l,light_insert_cmp); + } + + l = nearby; + for (i=0; l; i++) { + shader_uniform_light(s,i,l); + l = l->next; + } + for (; i<8; i++) { + shader_uniform_light(s,i,NULL); + } +} diff --git a/src/graphics/material.c b/src/graphics/material.c index 6d6e067..499d1dd 100644 --- a/src/graphics/material.c +++ b/src/graphics/material.c @@ -20,25 +20,39 @@ #include "common.h" #include "graphics.h" #include "list.h" +#include "array.h" #include static struct { material_t *materials; int ids; - GLuint current_texture; + GLuint current_texture[8]; uint8_t culling; uint8_t blended; GLenum blend_mode; } mat_data ={ NULL, 0, - 0, + {0,0,0,0,0,0,0,0}, 0, 0, GL_ZERO }; +material_t *mat_find(char* name) +{ + material_t *m = mat_data.materials; + + while (m) { + if (!strcmp(m->name,name)) + return m; + m = m->next; + } + + return m; +} + /* create a new blank material */ material_t *mat_create() { @@ -46,7 +60,7 @@ material_t *mat_create() mat->id = mat_data.ids++; mat->name[0] = 0; mat->options = MATOPT_BFCULL; - mat->tex = NULL; + array_init(&mat->textures,ARRAY_TYPE_PTR); mat->next = NULL; mat->shininess = 1.0; mat->reflectivity = 0.0; @@ -60,13 +74,17 @@ material_t *mat_create() /* free a material */ void mat_free(material_t *mat) { + texture_t *tex; if (!mat) return; mat_data.materials = list_remove(&mat_data.materials,mat); - if (mat->tex) - tex_free(mat->tex); + while ((tex = array_pop_ptr(&mat->textures))) { + tex_free(tex); + } + + array_free(&mat->textures,0); free(mat); } @@ -75,7 +93,7 @@ void mat_free(material_t *mat) material_t *mat_from_tex(texture_t *tex) { material_t *mat = mat_create(); - mat->tex = tex; + array_push_ptr(&mat->textures,tex); strcpy(mat->name,tex->name); return mat; @@ -84,77 +102,97 @@ material_t *mat_from_tex(texture_t *tex) /* create a material from pixel data */ material_t *mat_from_pixels(image_t *p) { + texture_t *tex; material_t *mat = mat_create(); - mat->tex = tex_from_pixels(p); - strcpy(mat->name,mat->tex->name); + tex = tex_from_pixels(p); + array_push_ptr(&mat->textures,tex); + strcpy(mat->name,tex->name); return mat; } -/* update a material from pixel data */ -material_t *mat_update_pixels(material_t *mat, image_t *p) +/* create a material from an image */ +material_t *mat_from_image(char* type, char* file) { - if (!mat) - return mat_from_pixels(p); + texture_t *tex; + material_t *mat; + + tex = tex_from_image(type,file); + if (!tex) + return NULL; - mat->tex = tex_update_pixels(mat->tex,p); + mat = mat_create(); + array_push_ptr(&mat->textures,tex); + + strcpy(mat->name,tex->name); return mat; } -/* create a material from an image */ -material_t *mat_from_image(char* type, char* file) +/* combine size images into a texture cube */ +material_t *mat_from_box(char* front, char* back, char* left, char* right, char* top, char* bottom) { - material_t *mat = mat_create(); + texture_t *tex; + material_t *mat; - mat->tex = tex_from_image(type,file); - if (!mat->tex) { - mat_free(mat); + tex = tex_from_box(front,back,left,right,top,bottom); + if (!tex) return NULL; - } - strcpy(mat->name,mat->tex->name); + mat = mat_create(); + array_push_ptr(&mat->textures,tex); + + strcpy(mat->name,tex->name); return mat; } +/* add a second texture to a material from an image */ +int mat_add_image(material_t *mat, char* type, char* file) +{ + texture_t *tex; + tex = tex_from_image(type,file); + if (!tex) + return 1; + + array_push_ptr(&mat->textures,tex); + + return 0; +} + +/* add a new texture to a material */ +int mat_add_tex(material_t *mat, texture_t *tex) +{ + if (!tex) + return 1; + + array_push_ptr(&mat->textures,tex); + + return 0; +} + /* create a material from a colour */ material_t *mat_from_colour(colour_t *c) { - char buff[100]; + char buff[256]; + texture_t *tex; material_t *mat; - snprintf(buff,100,"rgba-%d-%d-%d-%d",c->r,c->g,c->b,c->a); + snprintf(buff,256,"rgba-%d-%d-%d-%d",c->r,c->g,c->b,c->a); - mat = mat_create(); - - mat->tex = tex_from_rgba(1,1,c->r,c->g,c->b,c->a); - if (!mat->tex) { - mat_free(mat); + tex = tex_from_rgba(1,1,c->r,c->g,c->b,c->a); + if (!tex) return NULL; - } + + mat = mat_create(); + array_push_ptr(&mat->textures,tex); strcpy(mat->name,buff); return mat; } -/* bind a texture and apply options */ -int mat_bind_with_opts(GLuint tex, uint32_t options) +static void mat_apply_opts(uint32_t options) { - GLenum e; - - if (mat_data.current_texture != tex) - glBindTexture(GL_TEXTURE_2D,tex); - - e = glGetError(); - if (e != GL_NO_ERROR) { - char* es = opengl_error_string(e); - vlprintf(CN_ERROR, "%s",es); - return 1; - } - - mat_data.current_texture = tex; - /* back face culling */ if ((options&MATOPT_BFCULL) == MATOPT_BFCULL) { if (!mat_data.culling) { @@ -205,6 +243,66 @@ int mat_bind_with_opts(GLuint tex, uint32_t options) }else{ shader_uniform_float(NULL,"alphafunc",0.0); } +} + +static void mat_bind(GLuint tex, GLenum type, uint8_t slot) +{ + char buff[32]; + if (slot < 0 || slot > 7) + return; + + if (mat_data.current_texture[slot] == tex) + return; + + switch (slot) { + case 0: + glActiveTexture(GL_TEXTURE0); + break; + case 1: + glActiveTexture(GL_TEXTURE1); + break; + case 2: + glActiveTexture(GL_TEXTURE2); + break; + case 3: + glActiveTexture(GL_TEXTURE3); + break; + case 4: + glActiveTexture(GL_TEXTURE4); + break; + case 5: + glActiveTexture(GL_TEXTURE5); + break; + case 6: + glActiveTexture(GL_TEXTURE6); + break; + case 7: + glActiveTexture(GL_TEXTURE7); + break; + default: + return; + } + + snprintf(buff,32,"texture%u",slot); + + glBindTexture(type,tex); + + mat_data.current_texture[slot] = tex; + + shader_uniform_int(NULL,buff,slot); +} + +/* bind a texture and apply options */ +int mat_bind_with_opts(GLuint tex, uint32_t options) +{ + uint8_t i; + mat_bind(tex,GL_TEXTURE_2D,0); + mat_apply_opts(options); + + for (i=1; i<8; i++) { + mat_bind(0,GL_TEXTURE_2D,i); + } + return 0; } @@ -212,11 +310,20 @@ int mat_bind_with_opts(GLuint tex, uint32_t options) /* use a material */ void mat_use(material_t *mat, shader_t *shader) { - if (mat->tex) { - if (mat->tex->state != 1) - tex_generate(mat->tex); - if (mat_bind_with_opts(mat->tex->glid,mat->options)) - mat->tex->state = 0; + if (mat->textures.length) { + texture_t *tex; + int i; + for (i=0; i<8; i++) { + tex = array_get_ptr(&mat->textures,i); + if (tex) { + if (tex->state != 1) + tex_generate(tex); + mat_bind(tex->glid,tex->type,i); + }else if (mat_data.current_texture[i]) { + mat_bind(0,GL_TEXTURE_2D,i); + } + } + mat_apply_opts(mat->options); }else{ mat_bind_with_opts(0,mat->options); } @@ -243,20 +350,7 @@ void mat_bumpiness(material_t *mat, float bumpiness) /* set the name of a material */ void mat_name(material_t *mat, char* name) { - strncpy(mat->name,name,100); -} - -/* set the texture of a material */ -void mat_tex(material_t *mat, texture_t *tex) -{ - mat->tex = tex; -} - -/* set the texture of a material from an image file */ -void mat_tex_file(material_t *mat, char* type, char* file) -{ - mat->tex = tex_from_image(type,file); - strcpy(mat->name,mat->tex->name); + strncpy(mat->name,name,256); } /* set the options for a material, return the previous options */ diff --git a/src/graphics/object.c b/src/graphics/object.c index 7a4e1e0..a12e27e 100644 --- a/src/graphics/object.c +++ b/src/graphics/object.c @@ -62,7 +62,6 @@ object_t *object_create(v3_t *pos) { object_t *o = NULL; return o; - /* TODO: uncomment this render3d_object_create(); */ o->pos.x = pos->x; o->pos.y = pos->y; o->pos.z = pos->z; @@ -74,7 +73,6 @@ object_t *object_create(v3_t *pos) o->ignore = 0; o->drop = 0; - o->abounds = NULL; o->bounds.max.x = 0.0; o->bounds.max.y = 0.0; o->bounds.max.z = 0.0; @@ -255,3 +253,42 @@ void object_calc_normals(object_t *o) mesh_calc_normals(m); } } + +/* calculate normals for an object */ +void object_calc_bounds(object_t *o) +{ + v3_t min = {1000.0,1000.0,1000.0}; + v3_t max = {-1000.0,-1000.0,-1000.0}; + int i; + int k; + int l; + mesh_t **m; + v3_t *v; + + m = o->meshes->data; + for (i=0; imeshes->length; i++) { + v = m[i]->v->data; + l = m[i]->v->length/3; + for (k=0; k max.x) + max.x = v[k].x; + if (v[k].y > max.y) + max.y = v[k].y; + if (v[k].z > max.z) + max.z = v[k].z; + } + } + + o->bounds.min.x = min.x*o->scale.x; + o->bounds.min.y = min.y*o->scale.y; + o->bounds.min.z = min.z*o->scale.z; + o->bounds.max.x = max.x*o->scale.x; + o->bounds.max.y = max.y*o->scale.y; + o->bounds.max.z = max.z*o->scale.z; +} diff --git a/src/graphics/opengl.c b/src/graphics/opengl.c index 6b4fa6c..b02538f 100644 --- a/src/graphics/opengl.c +++ b/src/graphics/opengl.c @@ -33,6 +33,8 @@ static struct { int cfg_particles_max; int cfg_bumpmap; int cfg_pseudosdf; + int cfg_max_shadow_passes; + int cfg_shadow_size; } opengl_features = { -1, 1.0, @@ -43,7 +45,9 @@ static struct { 1, 1000, 1, - 1 + 1, + 1, + 512 }; /* command anisotropic setter */ @@ -94,6 +98,18 @@ int opengl_psdf_setter(char* value) opengl_features.cfg_pseudosdf = parse_bool(value); return 0; } +/* command shadowpass setter */ +int opengl_shadowpass_setter(char* value) +{ + opengl_features.cfg_max_shadow_passes = strtol(value,NULL,10); + return 0; +} +/* command shadowsize setter */ +int opengl_shadowsize_setter(char* value) +{ + opengl_features.cfg_shadow_size = strtol(value,NULL,10); + return 0; +} /* check for anisotropic filtering support */ int opengl_has_anisotropic() @@ -161,6 +177,18 @@ int opengl_has_psdf() return opengl_features.cfg_pseudosdf; } +/* get the maximum number of shadow passes allowed */ +int opengl_get_shadow_passes() +{ + return opengl_features.cfg_max_shadow_passes; +} + +/* get the size of the shadow texture */ +int opengl_get_shadow_size() +{ + return opengl_features.cfg_shadow_size; +} + /* converts an opengl error enum into a string */ char* opengl_error_string(GLenum e) { diff --git a/src/graphics/particles.c b/src/graphics/particles.c new file mode 100644 index 0000000..5627686 --- /dev/null +++ b/src/graphics/particles.c @@ -0,0 +1,272 @@ +/************************************************************************ +* particles.c +* voxelands - 3d voxel world sandbox game +* Copyright (C) Lisa 'darkrose' Milne 2016 +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +************************************************************************/ + +#include "common.h" +#include "graphics.h" +#include "list.h" + +static struct { + particle_emitter_t *emitters; + shader_t *shader; + GLuint vao; + GLuint vbo[2]; + int ids; + v3_t c_pos; +} particles_data = { + NULL, + NULL, + 0, + {0,0}, + 0 +}; + +static void particle_init(particle_t *p, v3_t *pos, v3_t *speed, float gravity, float life, float rotation, float scale) +{ + float f; + p->pos.x = pos->x; + p->pos.y = pos->y; + p->pos.z = pos->z; + + p->gravity = gravity*50.0; + p->rotation = rotation; + f = scale*0.125; + p->scale = math_rand_rangef(scale-f,scale+f); + + if (life > 0.0) { + f = life*0.5; + p->life = math_rand_rangef(life-f,life+f); + }else{ + p->life = life; + } + + p->speed.x = math_rand_rangef(speed->x-1.0,speed->x+1.0); + p->speed.y = math_rand_rangef(speed->y-1.0,speed->y+1.0); + p->speed.z = math_rand_rangef(speed->z-1.0,speed->z+1.0); + + p->dtime = 0.0; +} + +static int particle_create(particle_emitter_t *e, v3_t *pos, v3_t *speed, float gravity, float life, float rotation, float scale) +{ + particle_t *p; + + p = malloc(sizeof(particle_t)); + if (!p) + return 1; + + particle_init(p,pos,speed,gravity,life,rotation,scale); + + e->particles = list_push(&e->particles,p); + + return 0; +} +/* comparison functions: + * return 0 to insert + * return 1 to insert later + * return -1 to not insert at all + */ +static int particles_sort_cmp(void *e1, void *e2) +{ + float d1; + float d2; + particle_t *p1; + particle_t *p2; + + p1 = e1; + p2 = e2; + + d1 = math_distance(&particles_data.c_pos,&p1->pos); + if (d1 < 0) + d1 *= -1; + + d2 = math_distance(&particles_data.c_pos,&p2->pos); + if (d2 < 0) + d2 *= -1; + + /* return 1 if e1 is closer to the camera than e2 */ + if (d1 <= d2) + return 1; + return 0; +} + +particle_emitter_t *particles_emit(v3_t *pos, v3_t *dir, float life, float particle_life, float gravity, float scale, int frames, int count, material_t *mat) +{ + int i; + particle_emitter_t *e; + + e = malloc(sizeof(particle_emitter_t)); + if (!e) + return NULL; + + e->id = ++particles_data.ids; + e->mat = mat; + e->pos.x = pos->x; + e->pos.y = pos->y; + e->pos.z = pos->z; + e->dir.x = dir->x; + e->dir.y = dir->y; + e->dir.z = dir->z; + e->count = count; + e->gravity = gravity; + e->life = life; + e->scale = scale; + e->particle_life = particle_life; + e->frames = frames; + e->dtime = 0.0; + e->particles = NULL; + + particles_data.emitters = list_push(&particles_data.emitters,e); + + for (i=0; ix; + particles_data.c_pos.y = cam->y; + particles_data.c_pos.z = cam->z; + + projection = render_get_projection_matrix(); + + shader_uniform_matrix(particles_data.shader,"projectionMatrix",projection); + shader_uniform_matrix(particles_data.shader,"viewMatrix",&view); + + glBindVertexArray(particles_data.vao); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + dtime = client_dtime(); + + e = particles_data.emitters; + while (e) { + e->dtime += dtime; + + mat_use(e->mat,particles_data.shader); + + e->particles = list_resort_cmp(&e->particles,particles_sort_cmp); + + p = e->particles; + while (p) { + p->dtime += dtime; + + /* render it */ + matrix_init(&m); + m.data[0] = view.data[0]; + m.data[1] = view.data[4]; + m.data[2] = view.data[8]; + m.data[4] = view.data[1]; + m.data[5] = view.data[5]; + m.data[6] = view.data[9]; + m.data[8] = view.data[2]; + m.data[9] = view.data[6]; + m.data[10] = view.data[10]; + matrix_scale(&m,p->scale,p->scale,p->scale); + matrix_translate_v(&m,&p->pos); + shader_uniform_matrix(particles_data.shader,"transformationMatrix",&m); + shader_uniform_float(particles_data.shader,"frames",e->frames); + shader_uniform_float(particles_data.shader,"dframe",(e->frames*e->frames)/(p->life/p->dtime)); + + glDrawArrays(GL_TRIANGLE_STRIP,0,4); + pc++; + + if (p->life > 0.0 && p->dtime >= p->life) { + /* kill it if the emitter has expired */ + if (e->life > 0.0 && e->dtime >= e->life) { + rp = p; + p = p->next; + e->particles = list_remove(&e->particles,rp); + free(rp); + continue; + } + /* otherwise, reinitialise it as a new particle */ + particle_init(p,&e->pos,&e->dir,e->gravity,e->particle_life,0.0,e->scale); + }else{ + p->pos.x += p->speed.x*dtime; + p->pos.y += p->speed.y*dtime; + p->pos.z += p->speed.z*dtime; + if (p->gravity > 0.0) + p->speed.y -= p->gravity*dtime; + } + p = p->next; + } + + ec++; + + if (e->life > 0.0 && e->dtime >= e->life && !e->particles) { + re = e; + e = e->next; + particles_data.emitters = list_remove(&particles_data.emitters,re); + free(re); + continue; + } + e = e->next; + } + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glBindVertexArray(0); + + shader_disable(particles_data.shader); +} diff --git a/src/graphics/render.c b/src/graphics/render.c index d7e182e..7b06775 100644 --- a/src/graphics/render.c +++ b/src/graphics/render.c @@ -1,5 +1,5 @@ /************************************************************************ -* object.c +* render.c * voxelands - 3d voxel world sandbox game * Copyright (C) Lisa 'darkrose' Milne 2016 * @@ -21,19 +21,20 @@ #include "graphics.h" #include "ui.h" +#include + static struct { int ticks; int tticks; - int tpf; int fticks; int font_init; float dtime; + matrix_t projection; } render_data = { 0, 0, 0, 0, - 0, 0.1 }; @@ -43,18 +44,60 @@ float client_dtime() return render_data.dtime; } +/* get the current projection matrix */ +matrix_t *render_get_projection_matrix() +{ + return &render_data.projection; +} + +void render_set_projection_matrix(matrix_t *m) +{ + float fov; + float near_plane; + float far_plane; + float ratio; + float x; + float y; + float z; + + if (m) { + render_data.projection = *m; + return; + } + + fov = 70.0; + near_plane = 0.1; + far_plane = 1000.0; + + fov = math_degrees_to_radians(fov/2.0); + + ratio = (float)wm_data.size.width/(float)wm_data.size.height; + y = (1.0/tan(fov)); + x = y/ratio; + z = far_plane-near_plane; + + matrix_init(&render_data.projection); + + render_data.projection.data[0] = x; + render_data.projection.data[5] = y; + render_data.projection.data[10] = -((far_plane+near_plane)/z); + render_data.projection.data[11] = -1; + render_data.projection.data[14] = -((2.0*near_plane*far_plane)/z); + render_data.projection.data[15] = 0; +} + /* clear the frame */ void render_pre() { if (!render_data.ticks) render_data.ticks = time_ticks(); - render_data.tpf = 1000/wm_data.frame_cap; events_main(); } /* render to frame */ void render_post() { + camera_t *cam; ui_render(); if (wm_data.cursor.mat) { @@ -63,11 +106,24 @@ void render_post() render2d_quad_mat(wm_data.cursor.mat,mouse[0]+wm_data.cursor.x,mouse[1]+wm_data.cursor.y,wm_data.cursor.w,wm_data.cursor.h); } + cam = camera_get(); + /* should get this from sky when in-game */ - glClearColor(0, 0, 0, 1.0); + glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + +/* water_prerender(cam); + + render_map(cam,NULL); + + water_render(); +*/ + render3d(cam,NULL); + + particles_render(); - render3d(); + glDisable(GL_DEPTH_TEST); render2d(); diff --git a/src/graphics/render3d.c b/src/graphics/render3d.c index c785b12..cc2e856 100644 --- a/src/graphics/render3d.c +++ b/src/graphics/render3d.c @@ -28,7 +28,7 @@ static struct { array_t *objects; object_t *sorted; shader_t *shader; - matrix_t projection; + float frustum[6][4]; matrix_t view; } render3d_data = { NULL, @@ -41,6 +41,8 @@ static int render3d_sort(void *e1, void *e2) camera_t *c; v3_t cp; v3_t ep; + object_t *o1; + object_t *o2; GLfloat d1; GLfloat d2; c = camera_get(); @@ -48,22 +50,19 @@ static int render3d_sort(void *e1, void *e2) cp.y = c->y; cp.z = c->z; - ep.x = ((object_t*)e1)->pos.x; - ep.y = ((object_t*)e1)->pos.y; - ep.z = ((object_t*)e1)->pos.z; + o1 = (object_t*)e1; + o2 = (object_t*)e2; + + ep.x = o1->pos.x; + ep.y = o1->pos.y; + ep.z = o1->pos.z; d1 = math_distance(&cp,&ep); if (d1 < 0) d1 *= -1; - /* return -1 if this object is out of visual range */ - if (d1 > wm_data.distance) - return -1; - - /* TODO: return -1 if this object is completely behind the camera */ - - ep.x = ((object_t*)e2)->pos.x; - ep.y = ((object_t*)e2)->pos.y; - ep.z = ((object_t*)e2)->pos.z; + ep.x = o2->pos.x; + ep.y = o2->pos.y; + ep.z = o2->pos.z; d2 = math_distance(&cp,&ep); if (d2 < 0) d2 *= -1; @@ -74,21 +73,6 @@ static int render3d_sort(void *e1, void *e2) return 0; } -static void render3d_step(object_t *o) -{ - /* - if (o->m->step(o)) { - int i; - mesh_t *m; - for (i=0; imeshes->length; i++) { - m = ((mesh_t**)o->meshes->data)[i]; - if (m->vbo.state == 1) - m->vbo.state = 2; - } - } - */ -} - static void render3d_genvao(mesh_t *m) { if (!m->v->length || !m->i->length) @@ -126,10 +110,6 @@ static void render3d_genvao(mesh_t *m) m->vao.state = 1; } -static void render3d_regenvao(mesh_t *m) -{ -} - /* find a 3d object */ object_t *render3d_object_find(int id) { @@ -161,10 +141,12 @@ void render3d_object_free(object_t *o) ((unsigned char**)(render3d_data.objects->data))[i] = NULL; - while ((m = array_pop_ptr(o->meshes))) { - mesh_free(m); + if (!o->m) { + while ((m = array_pop_ptr(o->meshes))) { + mesh_free(m); + } + array_free(o->meshes,1); } - array_free(o->meshes,1); free(o); } @@ -176,6 +158,9 @@ object_t *render3d_object_create() o->meshes = array_create(ARRAY_TYPE_PTR); o->id = object_ids++; + o->anim.skeleton = 0; + o->anim.frame = 0; + o->anim.value = 0.0; o->ignore = 1; o->drop = 0; o->m = NULL; @@ -189,6 +174,13 @@ object_t *render3d_object_create() o->scale.y = 1.0; o->scale.z = 1.0; + o->bounds.max.x = 0.0; + o->bounds.max.y = 0.0; + o->bounds.max.z = 0.0; + o->bounds.min.x = 0.0; + o->bounds.min.y = 0.0; + o->bounds.min.z = 0.0; + if (!render3d_data.objects) render3d_data.objects = array_create(ARRAY_TYPE_PTR); @@ -200,8 +192,6 @@ object_t *render3d_object_create() /* render a model */ object_t *render3d_model(model_t *mod, v3_t *pos) { - int i; - mesh_t *m; object_t *o = render3d_object_create(); o->pos.x = pos->x; o->pos.y = pos->y; @@ -209,29 +199,12 @@ object_t *render3d_model(model_t *mod, v3_t *pos) o->m = mod; - for (i=0; imeshes->length; i++) { - m = ((mesh_t**)(mod->meshes->data))[i]; - m = mesh_copy(m); - array_push_ptr(o->meshes,m); - } - - o->ignore = 0; - - return o; -} + array_free(o->meshes,1); -/* render a mesh */ -object_t *render3d_mesh(mesh_t *m, v3_t *pos) -{ - object_t *o = render3d_object_create(); - o->pos.x = pos->x; - o->pos.y = pos->y; - o->pos.z = pos->z; + o->meshes = mod->meshes; o->ignore = 0; - array_push_ptr(o->meshes,m); - return o; } @@ -242,27 +215,22 @@ object_t *render3d_cube(float scale, v3_t *pos, material_t *mat) {0.5,-0.5,-0.5}, {-0.5,-0.5,-0.5}, {-0.5,0.5,-0.5}, - {-0.5,0.5,0.5}, {-0.5,-0.5,0.5}, {0.5,-0.5,0.5}, {0.5,0.5,0.5}, - {0.5,0.5,0.5}, {0.5,-0.5,0.5}, {0.5,-0.5,-0.5}, {0.5,0.5,-0.5}, - {-0.5,0.5,-0.5}, {-0.5,-0.5,-0.5}, {-0.5,-0.5,0.5}, {-0.5,0.5,0.5}, - {0.5,0.5,0.5}, {0.5,0.5,-0.5}, {-0.5,0.5,-0.5}, {-0.5,0.5,0.5}, - {-0.5,-0.5,0.5}, {-0.5,-0.5,-0.5}, {0.5,-0.5,-0.5}, @@ -314,9 +282,7 @@ object_t *render3d_cube(float scale, v3_t *pos, material_t *mat) o->pos.x = pos->x; o->pos.y = pos->y; o->pos.z = pos->z; - m = mesh_create_material(mat); - for (i=0; i<24; i++) { array_push_v2t(m->t,&t[i]); v[i].x *= scale; @@ -327,59 +293,95 @@ object_t *render3d_cube(float scale, v3_t *pos, material_t *mat) for (i=0; i<36; i++) { array_push_int(m->i,indices[i]); } - array_push_ptr(o->meshes,m); - object_calc_normals(o); - o->ignore = 0; - return o; } -void render3d_set_projection_matrix() +int render3d_point_in_frustum(v3_t *p) { - float fov; - float near_plane; - float far_plane; - float ratio; - float x; - float y; - float z; - - fov = 70.0; - near_plane = 0.1; - far_plane = 1000.0; - - fov = math_degrees_to_radians(fov/2.0); - - ratio = (float)wm_data.size.width/(float)wm_data.size.height; - y = (1.0/tan(fov)); - x = y/ratio; - z = far_plane-near_plane; - - matrix_init(&render3d_data.projection); - - render3d_data.projection.data[0] = x; - render3d_data.projection.data[5] = y; - render3d_data.projection.data[10] = -((far_plane+near_plane)/z); - render3d_data.projection.data[11] = -1; - render3d_data.projection.data[14] = -((2.0*near_plane*far_plane)/z); - render3d_data.projection.data[15] = 0; + int i; + for (i=0; i<6; i++) { + if (((render3d_data.frustum[i][0]*p->x)+(render3d_data.frustum[i][1]*p->y)+(render3d_data.frustum[i][2]*p->z)+render3d_data.frustum[i][3]) <= 0) + return 0; + } + return 1; +} + +int render3d_bounds_in_frustum(v3_t *p, aabox_t *b) +{ + v3_t v[8]; + int i; + int k; + + if (render3d_point_in_frustum(p)) + return 1; + + v[0].x = b->min.x; + v[0].y = b->min.y; + v[0].z = b->min.z; + + v[1].x = b->max.x; + v[1].y = b->min.y; + v[1].z = b->min.z; + + v[2].x = b->min.x; + v[2].y = b->max.y; + v[2].z = b->min.z; + + v[3].x = b->max.x; + v[3].y = b->max.y; + v[3].z = b->min.z; + + v[4].x = b->min.x; + v[4].y = b->min.y; + v[4].z = b->max.z; + + v[5].x = b->max.x; + v[5].y = b->min.y; + v[5].z = b->max.z; + + v[6].x = b->min.x; + v[6].y = b->max.y; + v[6].z = b->max.z; + + v[7].x = b->max.x; + v[7].y = b->max.y; + v[7].z = b->max.z; + + for (i=0; i<6; i++) { + for (k=0; k<8; k++) { + if ((( + render3d_data.frustum[i][0]*v[k].x) + +(render3d_data.frustum[i][1]*v[k].y) + +(render3d_data.frustum[i][2]*v[k].z) + +render3d_data.frustum[i][3]) > 0 + ) + break; + } + if (k == 8) + return 0; + } + + return 1; } /* render 3d graphics to the frame */ -void render3d() +void render3d(camera_t *cam, v4_t *plane) { + static v4_t p = {1000000.0,0.0,-1.0,0.0}; int i; object_t *o; mesh_t *m; matrix_t mat; + matrix_t *projection; shader_t *active_shader; + float t; + GLuint active_vao = 0; if (!render3d_data.objects || !render3d_data.objects->length) return; - glEnable(GL_DEPTH_TEST); if (!render3d_data.shader) { render3d_data.shader = shader_create("model"); shader_attribute(render3d_data.shader,0,"position"); @@ -391,10 +393,100 @@ void render3d() shader_enable(render3d_data.shader); active_shader = render3d_data.shader; - camera_view_matrix(&render3d_data.view); + camera_view_matrix(&render3d_data.view,cam); + projection = render_get_projection_matrix(); - shader_uniform_matrix(active_shader,"projectionMatrix",&render3d_data.projection); + shader_uniform_matrix(active_shader,"projectionMatrix",projection); shader_uniform_matrix(active_shader,"viewMatrix",&render3d_data.view); + if (plane) { + glEnable(GL_CLIP_DISTANCE0); + }else{ + glDisable(GL_CLIP_DISTANCE0); + plane = &p; + } + shader_uniform_v4(active_shader,"plane",plane); + + /* calculate the frustum */ + mat = *projection; + matrix_multiply(&mat,&render3d_data.view); + + /* Extract the numbers for the RIGHT plane */ + render3d_data.frustum[0][0] = mat.data[ 3] - mat.data[ 0]; + render3d_data.frustum[0][1] = mat.data[ 7] - mat.data[ 4]; + render3d_data.frustum[0][2] = mat.data[11] - mat.data[ 8]; + render3d_data.frustum[0][3] = mat.data[15] - mat.data[12]; + + /* Normalize the result */ + t = sqrt( render3d_data.frustum[0][0] * render3d_data.frustum[0][0] + render3d_data.frustum[0][1] * render3d_data.frustum[0][1] + render3d_data.frustum[0][2] * render3d_data.frustum[0][2] ); + render3d_data.frustum[0][0] /= t; + render3d_data.frustum[0][1] /= t; + render3d_data.frustum[0][2] /= t; + render3d_data.frustum[0][3] /= t; + + /* Extract the numbers for the LEFT plane */ + render3d_data.frustum[1][0] = mat.data[ 3] + mat.data[ 0]; + render3d_data.frustum[1][1] = mat.data[ 7] + mat.data[ 4]; + render3d_data.frustum[1][2] = mat.data[11] + mat.data[ 8]; + render3d_data.frustum[1][3] = mat.data[15] + mat.data[12]; + + /* Normalize the result */ + t = sqrt( render3d_data.frustum[1][0] * render3d_data.frustum[1][0] + render3d_data.frustum[1][1] * render3d_data.frustum[1][1] + render3d_data.frustum[1][2] * render3d_data.frustum[1][2] ); + render3d_data.frustum[1][0] /= t; + render3d_data.frustum[1][1] /= t; + render3d_data.frustum[1][2] /= t; + render3d_data.frustum[1][3] /= t; + + /* Extract the BOTTOM plane */ + render3d_data.frustum[2][0] = mat.data[ 3] + mat.data[ 1]; + render3d_data.frustum[2][1] = mat.data[ 7] + mat.data[ 5]; + render3d_data.frustum[2][2] = mat.data[11] + mat.data[ 9]; + render3d_data.frustum[2][3] = mat.data[15] + mat.data[13]; + + /* Normalize the result */ + t = sqrt( render3d_data.frustum[2][0] * render3d_data.frustum[2][0] + render3d_data.frustum[2][1] * render3d_data.frustum[2][1] + render3d_data.frustum[2][2] * render3d_data.frustum[2][2] ); + render3d_data.frustum[2][0] /= t; + render3d_data.frustum[2][1] /= t; + render3d_data.frustum[2][2] /= t; + render3d_data.frustum[2][3] /= t; + + /* Extract the TOP plane */ + render3d_data.frustum[3][0] = mat.data[ 3] - mat.data[ 1]; + render3d_data.frustum[3][1] = mat.data[ 7] - mat.data[ 5]; + render3d_data.frustum[3][2] = mat.data[11] - mat.data[ 9]; + render3d_data.frustum[3][3] = mat.data[15] - mat.data[13]; + + /* Normalize the result */ + t = sqrt( render3d_data.frustum[3][0] * render3d_data.frustum[3][0] + render3d_data.frustum[3][1] * render3d_data.frustum[3][1] + render3d_data.frustum[3][2] * render3d_data.frustum[3][2] ); + render3d_data.frustum[3][0] /= t; + render3d_data.frustum[3][1] /= t; + render3d_data.frustum[3][2] /= t; + render3d_data.frustum[3][3] /= t; + + /* Extract the FAR plane */ + render3d_data.frustum[4][0] = mat.data[ 3] - mat.data[ 2]; + render3d_data.frustum[4][1] = mat.data[ 7] - mat.data[ 6]; + render3d_data.frustum[4][2] = mat.data[11] - mat.data[10]; + render3d_data.frustum[4][3] = mat.data[15] - mat.data[14]; + + /* Normalize the result */ + t = sqrt( render3d_data.frustum[4][0] * render3d_data.frustum[4][0] + render3d_data.frustum[4][1] * render3d_data.frustum[4][1] + render3d_data.frustum[4][2] * render3d_data.frustum[4][2] ); + render3d_data.frustum[4][0] /= t; + render3d_data.frustum[4][1] /= t; + render3d_data.frustum[4][2] /= t; + render3d_data.frustum[4][3] /= t; + + /* Extract the NEAR plane */ + render3d_data.frustum[5][0] = mat.data[ 3] + mat.data[ 2]; + render3d_data.frustum[5][1] = mat.data[ 7] + mat.data[ 6]; + render3d_data.frustum[5][2] = mat.data[11] + mat.data[10]; + render3d_data.frustum[5][3] = mat.data[15] + mat.data[14]; + + /* Normalize the result */ + t = sqrt( render3d_data.frustum[5][0] * render3d_data.frustum[5][0] + render3d_data.frustum[5][1] * render3d_data.frustum[5][1] + render3d_data.frustum[5][2] * render3d_data.frustum[5][2] ); + render3d_data.frustum[5][0] /= t; + render3d_data.frustum[5][1] /= t; + render3d_data.frustum[5][2] /= t; + render3d_data.frustum[5][3] /= t; render3d_data.sorted = NULL; @@ -412,9 +504,17 @@ void render3d() continue; } /* call step on each object, this may modify the data (such as with animated models) */ - if (o->m && o->m->step) - render3d_step(o); - /* sort objects by distance, ignoring anything that can't be seen */ + if (o->m && o->m->step) { + o->m->step(o); + object_calc_bounds(o); + }else if (o->bounds.min.x == o->bounds.max.x && o->bounds.min.y == o->bounds.max.y && o->bounds.min.z == o->bounds.max.z) { + object_calc_bounds(o); + } + /* ignore anything that can't be seen */ + if (!render3d_bounds_in_frustum(&o->pos,&o->bounds)) + continue; + + /* sort objects by distance */ render3d_data.sorted = list_insert_cmp(&render3d_data.sorted,o,render3d_sort); } @@ -428,34 +528,37 @@ void render3d() matrix_rotate_deg_x(&mat,o->rot.x); matrix_translate_v(&mat,&o->pos); shader_uniform_matrix(active_shader,"transformationMatrix",&mat); + light_bind_near(render3d_data.shader,&o->pos); for (i=0; imeshes->length; i++) { m = ((mesh_t**)o->meshes->data)[i]; /* create buffers if necessary and fill with data */ - if (!m->vao.state) { + if (!m->vao.state) render3d_genvao(m); - }else if (m->vao.state == 2) { - render3d_regenvao(m); - } if (!m->vao.list) continue; - glBindVertexArray(m->vao.list); - glEnableVertexAttribArray(0); + if (m->vao.list != active_vao) { + glBindVertexArray(m->vao.list); + glEnableVertexAttribArray(0); - mat_use(m->mat,active_shader); + /* use vertex, normal, and texcoord or colour arrays */ + if (m->vao.normals) { + glEnableVertexAttribArray(1); + }else{ + glDisableVertexAttribArray(1); + } + if (m->vao.texcoords) { + glEnableVertexAttribArray(2); + }else{ + glDisableVertexAttribArray(2); + } - /* use vertex, normal, and texcoord or colour arrays */ - if (m->vao.normals) { - glEnableVertexAttribArray(1); - }else{ - glDisableVertexAttribArray(1); - } - if (m->vao.texcoords) { - glEnableVertexAttribArray(2); - }else{ - glDisableVertexAttribArray(2); + active_vao = m->vao.list; } + + mat_use(m->mat,active_shader); + if (m->option) { switch(m->mode) { case GL_POINTS: @@ -482,6 +585,10 @@ void render3d() } o = o->next; } + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); glBindVertexArray(0); shader_disable(active_shader); diff --git a/src/graphics/shader.c b/src/graphics/shader.c index 04c8db5..5aa322b 100644 --- a/src/graphics/shader.c +++ b/src/graphics/shader.c @@ -167,13 +167,15 @@ int shader_attribute(shader_t *s, int att, char* name) /* set a shader uniform value */ int shader_uniform_int(shader_t *s, char* name, int value) { - GLuint var; + GLint var; if (!s) s = active; if (!s) return 1; var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; glUniform1i(var,value); return 0; @@ -182,13 +184,15 @@ int shader_uniform_int(shader_t *s, char* name, int value) /* set a shader uniform value */ int shader_uniform_float(shader_t *s, char* name, float value) { - GLuint var; + GLint var; if (!s) s = active; if (!s) return 1; var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; glUniform1f(var,value); return 0; @@ -197,13 +201,15 @@ int shader_uniform_float(shader_t *s, char* name, float value) /* set a shader uniform value */ int shader_uniform_v2(shader_t *s, char* name, v2_t *value) { - GLuint var; + GLint var; if (!s) s = active; if (!s) return 1; var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; glUniform2f(var,value->x,value->y); return 0; @@ -212,33 +218,107 @@ int shader_uniform_v2(shader_t *s, char* name, v2_t *value) /* set a shader uniform value */ int shader_uniform_v3(shader_t *s, char* name, v3_t *value) { - GLuint var; + GLint var; if (!s) s = active; if (!s) return 1; var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; glUniform3f(var,value->x,value->y,value->z); return 0; } /* set a shader uniform value */ +int shader_uniform_v4(shader_t *s, char* name, v4_t *value) +{ + GLint var; + if (!s) + s = active; + if (!s) + return 1; + + var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; + + glUniform4f(var,value->x,value->y,value->z,value->w); + + return 0; +} + +/* set a shader uniform value */ +int shader_uniform_colour(shader_t *s, char* name, colour_t *value) +{ + GLint var; + GLfloat r; + GLfloat g; + GLfloat b; + GLfloat a; + if (!s) + s = active; + if (!s) + return 1; + + var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; + + r = (float)value->r/255.0; + g = (float)value->g/255.0; + b = (float)value->b/255.0; + a = (float)value->a/255.0; + + glUniform4f(var,r,g,b,a); + + return 0; +} + +/* set a shader uniform value */ int shader_uniform_matrix(shader_t *s, char* name, matrix_t *value) { - GLuint var; + GLint var; if (!s) s = active; if (!s) return 1; var = glGetUniformLocation(s->program,name); + if (var < 0) + return 1; glUniformMatrix4fv(var,1,GL_FALSE,value->data); return 0; } +/* bind all 3 uniforms for a light */ +int shader_uniform_light(shader_t *s, int slot, light_t *light) +{ + char buff[256]; + + if (!light) { + snprintf(buff,256,"light%d_active",slot); + return shader_uniform_int(s,buff,0); + } + + snprintf(buff,256,"light%d_active",slot); + shader_uniform_int(s,buff,1); + + snprintf(buff,256,"light%d_pos",slot); + shader_uniform_v3(s,buff,&light->pos); + + snprintf(buff,256,"light%d_att",slot); + shader_uniform_v3(s,buff,&light->att); + + snprintf(buff,256,"light%d_colour",slot); + shader_uniform_colour(s,buff,&light->colour); + + return 0; +} + /* use a shader */ int shader_enable(shader_t *s) { diff --git a/src/graphics/texture.c b/src/graphics/texture.c index 096c5d5..e858a43 100644 --- a/src/graphics/texture.c +++ b/src/graphics/texture.c @@ -23,26 +23,44 @@ #include -static texture_t *textures = NULL; -static int tex_ids = 0; +static struct { + texture_t *textures; + int ids; +} tex_data = { + NULL, + 0 +}; /* generate the hardware texture */ int tex_generate(texture_t *tex) { + GLenum types[6] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y + }; + int i; + int c; int b = 0; int t = 0; int m = 0; + GLenum type; GLenum e; if (!tex) return 1; + e = glGetError(); + /* delete the old texture, if it exists */ if (tex->state) { glDeleteTextures(1, &tex->glid); e = glGetError(); if (e != GL_NO_ERROR) { char* es = opengl_error_string(e); - vlprintf(CN_ERROR, "%s",es); + vlprintf(CN_ERROR, "%d %s",__LINE__,es); return 1; } } @@ -52,15 +70,16 @@ int tex_generate(texture_t *tex) e = glGetError(); if (e != GL_NO_ERROR) { char* es = opengl_error_string(e); - vlprintf(CN_ERROR, "%s",es); + vlprintf(CN_ERROR, "%d %s",__LINE__,es); return 1; } - glBindTexture(GL_TEXTURE_2D, tex->glid); + glActiveTexture(GL_TEXTURE0); + glBindTexture(tex->type, tex->glid); e = glGetError(); if (e != GL_NO_ERROR) { char* es = opengl_error_string(e); - vlprintf(CN_ERROR, "%s",es); + vlprintf(CN_ERROR, "%d %s",__LINE__,es); return 1; } @@ -68,50 +87,63 @@ int tex_generate(texture_t *tex) t = opengl_has_trilinear(); m = opengl_has_mipmap(); - /* draw the pixels to the texture */ - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex->px->w, tex->px->h , 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->px->pixels); - e = glGetError(); - if (e != GL_NO_ERROR) { - char* es = opengl_error_string(e); - vlprintf(CN_ERROR, "%s",es); - return 1; + c = 1; + if (tex->type == GL_TEXTURE_CUBE_MAP) + c = 6; + for (i=0; itype == GL_TEXTURE_CUBE_MAP) { + type = types[i]; + }else{ + type = GL_TEXTURE_2D; + } + /* draw the pixels to the texture */ + glTexImage2D(type, 0, GL_RGBA8, tex->px[i].w, tex->px[i].h , 0, GL_RGBA, GL_UNSIGNED_BYTE, tex->px[i].pixels); + e = glGetError(); + if (e != GL_NO_ERROR) { + char* es = opengl_error_string(e); + vlprintf(CN_ERROR, "%d %s",__LINE__,es); + return 1; + } } if (m) { - /* shouldn't ever need this, but there's an ATI/AMD bug that this fixes */ - glEnable(GL_TEXTURE_2D); - glGenerateMipmap(GL_TEXTURE_2D); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glGenerateMipmap(tex->type); + glTexParameteri(tex->type, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(tex->type, GL_TEXTURE_WRAP_T, GL_REPEAT); } if (t) { - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(tex->type,GL_TEXTURE_MAG_FILTER,GL_LINEAR); if (m) { - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(tex->type,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); }else{ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } }else if (b) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->type, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->type, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }else{ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(tex->type, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->type, GL_TEXTURE_MAG_FILTER, GL_NEAREST); } if (opengl_has_anisotropic()) { float ma = opengl_max_anisotropic(); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, ma); + glTexParameterf(tex->type, GL_TEXTURE_MAX_ANISOTROPY_EXT, ma); } e = glGetError(); if (e != GL_NO_ERROR) { char* es = opengl_error_string(e); - vlprintf(CN_ERROR, "%s",es); + vlprintf(CN_ERROR, "%d %s",__LINE__,es); return 1; } + if (tex->type == GL_TEXTURE_CUBE_MAP) { + 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); + } + tex->state = 1; return 0; @@ -130,11 +162,12 @@ texture_t *tex_create() tex->yf = 0; tex->name[0] = 0; tex->px = NULL; - tex->id = tex_ids++; + tex->id = tex_data.ids++; tex->glid = 0; + tex->type = GL_TEXTURE_2D; tex->state = 0; - textures = list_push(&textures,tex); + tex_data.textures = list_push(&tex_data.textures,tex); return tex; } @@ -144,9 +177,11 @@ void tex_free(texture_t *tex) { if (!tex) return; - textures = list_remove(&textures,tex); + tex_data.textures = list_remove(&tex_data.textures,tex); if (tex->glid) glDeleteTextures(1, &tex->glid); + if (tex->px && tex->type == GL_TEXTURE_CUBE_MAP) + free(tex->px); free(tex); } @@ -157,7 +192,7 @@ texture_t *tex_from_image(char* type, char* file) /* get the image */ image_t *p; - t = textures; + t = tex_data.textures; while (t) { if (!strcmp(t->name,file)) break; @@ -174,7 +209,61 @@ texture_t *tex_from_image(char* type, char* file) /* and make a texture out of it */ t = tex_from_pixels(p); if (t) - strncpy(t->name,file,100); + strncpy(t->name,file,256); + + return t; +} + +/* create a texture cube */ +texture_t *tex_from_box(char* front, char* back, char* left, char* right, char* top, char* bottom) +{ + int i; + texture_t *t; + image_t *p[6]; + + p[0] = image_load("texture",front); + if (!p[0]) + return NULL; + p[1] = image_load("texture",back); + if (!p[1]) + return NULL; + p[2] = image_load("texture",left); + if (!p[2]) + return NULL; + p[3] = image_load("texture",right); + if (!p[3]) + return NULL; + p[4] = image_load("texture",top); + if (!p[4]) + return NULL; + p[5] = image_load("texture",bottom); + if (!p[5]) + return NULL; + + t = tex_create(); + if (!t) + return NULL; + + snprintf(t->name,256,"box-%s-%s-%s-%s-%s-%s",front,back,left,right,top,bottom); + + t->type = GL_TEXTURE_CUBE_MAP; + + t->px = malloc(sizeof(image_t)*6); + if (!t->px) { + tex_free(t); + return NULL; + } + + t->w = p[0]->w; + t->h = p[0]->h; + t->xf = 1.0/(GLfloat)p[0]->w; + t->yf = 1.0/(GLfloat)p[0]->h; + + for (i=0; i<6; i++) { + t->px[i].w = p[i]->w; + t->px[i].h = p[i]->h; + t->px[i].pixels = p[i]->pixels; + } return t; } @@ -191,7 +280,7 @@ texture_t *tex_from_pixels(image_t *px) return NULL; tex->w = px->w; - tex->h = px->h ; + tex->h = px->h; tex->px = px; tex->xf = 1.0/(GLfloat)px->w; tex->yf = 1.0/(GLfloat)px->h; @@ -227,12 +316,12 @@ texture_t *tex_update_pixels(texture_t *tex, image_t *px) /* create a transparent texture */ texture_t *tex_from_rgba(int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t a) { - char n[100]; + char n[256]; texture_t *t; image_t *p; - snprintf(n,100,"rgba-%u-%u-%u-%u-%d-%d",(uint32_t)r,(uint32_t)g,(uint32_t)b,(uint32_t)a,x,y); - t = textures; + snprintf(n,256,"rgba-%u-%u-%u-%u-%d-%d",r,g,b,a,x,y); + t = tex_data.textures; while (t) { if (!strcmp(t->name,n)) break; diff --git a/src/graphics/wm_x11.c b/src/graphics/wm_x11.c index ab4ea03..7cf82a1 100644 --- a/src/graphics/wm_x11.c +++ b/src/graphics/wm_x11.c @@ -341,7 +341,7 @@ int wm_create() } /* MUST be done, else rendering gets messed up */ - render3d_set_projection_matrix(); + render_set_projection_matrix(NULL); return 0; } @@ -355,7 +355,7 @@ int wm_resize() XResizeWindow(wm_data.dpy, wm_data.win, wm_data.size.width, wm_data.size.height); /* MUST be done after a resize, else rendering gets messed up */ - render3d_set_projection_matrix(); + render_set_projection_matrix(NULL); return 0; } diff --git a/src/lib/list.c b/src/lib/list.c index d6691c2..a7ef963 100644 --- a/src/lib/list.c +++ b/src/lib/list.c @@ -219,3 +219,24 @@ void *list_insert_cmp(void *list, void *el, int (*list_cmp)(void *e1, void *e2)) return l; } + +/* resort a list, based on a compare function */ +void *list_resort_cmp(void *list, int (*list_cmp)(void *e1, void* e2)) +{ + ref_t *l = *((ref_t**)list); + ref_t *e = l; + ref_t *n; + + l = NULL; + + if (!list_cmp) + list_cmp = list_cmp_default; + + while (e) { + n = e->next; + l = list_insert_cmp(&l,e,list_cmp); + e = n; + } + + return l; +} diff --git a/src/server/dummy_commands.c b/src/server/dummy_commands.c index 669f876..58e393a 100644 --- a/src/server/dummy_commands.c +++ b/src/server/dummy_commands.c @@ -68,6 +68,14 @@ int opengl_bumpmap_setter(char* value) { return 0; } +int opengl_shadowpass_setter(char* value) +{ + return 0; +} +int opengl_shadowsize_setter(char* value) +{ + return 0; +} int opengl_psdf_setter(char* value) { return 0; -- 2.11.4.GIT