diff --git a/CMakeLists.txt b/CMakeLists.txt index b5dd58e..f023abd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,6 @@ install( ) install( - FILES resource/logo.png resource/font.png + FILES resource/logo.png resource/font.png resource/shadow.vs resource/shadow.fs DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/assaultfish ) diff --git a/client/gl.c b/client/gl.c index 5f56f95..04f7ba9 100644 --- a/client/gl.c +++ b/client/gl.c @@ -1,5 +1,8 @@ #include +#define SHADOW_WIDTH 1024 +#define SHADOW_HEIGHT 1024 + double gl_cam_lr = 0; double gl_cam_ud = 0; double gl_cam_x; @@ -8,9 +11,11 @@ double gl_cam_z; int gl_scene = AF_SCENE_MAIN; +static GLuint shadow_texture, shadow; + gl_scene_t gl_scenes[] = { - {gl_main_changed, gl_main_init, gl_main_draw}, /**/ - {NULL, NULL, NULL} /**/ + {gl_main_changed, gl_main_init, gl_main_draw, gl_main_after}, /**/ + {NULL, NULL, NULL, NULL} /**/ }; static char gl_status[256]; @@ -20,14 +25,8 @@ void gl_resize(int width, int height) { } void gl_init(void) { - GLfloat lightamb[] = {0.1, 0.1, 0.1, 1.0}; - GLfloat lightcol[] = {1.0, 1.0, 1.0, 1.0}; - const GLdouble genfunc[][4] = { - {1.0, 0.0, 0.0, 0.0}, - {0.0, 1.0, 0.0, 0.0}, - {0.0, 0.0, 1.0, 0.0}, - {0.0, 0.0, 0.0, 1.0}, - }; + GLfloat lightamb[] = {0.1, 0.1, 0.1, 1.0}; + GLfloat lightcol[] = {1.0, 1.0, 1.0, 1.0}; glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); @@ -52,6 +51,29 @@ void gl_init(void) { gl_font_init(); gl_status[0] = 0; + + glGenTextures(1, &shadow_texture); + glBindTexture(GL_TEXTURE_2D, shadow_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + + glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE); + + glBindTexture(GL_TEXTURE_2D, 0); + + if(gl_shader(&shadow, DATAROOTDIR "/assaultfish/shadow.vs", DATAROOTDIR "/assaultfish/shadow.fs")) { + glUseProgram(shadow); + glUniform1i(glGetUniformLocation(shadow, "texture"), 1); + } } void gl_cube(double x, double y, double z, double xs, double ys, double zs, double xr, double yr, double zr) { @@ -99,26 +121,98 @@ static void gl_common(void) { gl_font_text(gl_status, 0, 0, 1); } +static void scene(void) { + if(gl_scenes[gl_scene].draw != NULL) gl_scenes[gl_scene].draw(); +} + void gl_render(void) { - GLfloat lightpos[4] = {0, 5, 0, 1}; + GLfloat lightpos[4] = {2.5, 5, -2.5, 1}; + GLint viewport[4]; GLdouble modelview[16]; + GLdouble modelview2[16]; if(gl_scenes[gl_scene].init != NULL) gl_scenes[gl_scene].init(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); + + glGetIntegerv(GL_VIEWPORT, &viewport[0]); + + glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluPerspective(60, (double)SHADOW_WIDTH / SHADOW_HEIGHT, 0.01, 100.0); + gluLookAt(lightpos[0], lightpos[1], lightpos[2], 0, 0, 0, 0, 1, 0); + + glGetDoublev(GL_MODELVIEW_MATRIX, &modelview[0]); + + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + + glDisable(GL_LIGHTING); + + glCullFace(GL_FRONT); + + scene(); + + glBindTexture(GL_TEXTURE_2D, shadow_texture); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); + glBindTexture(GL_TEXTURE_2D, 0); + + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glEnable(GL_LIGHTING); + glCullFace(GL_BACK); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, (double)MwGetInteger(opengl, MwNwidth) / MwGetInteger(opengl, MwNheight), 0.01, 100.0); + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(gl_cam_x, gl_cam_y, gl_cam_z, gl_cam_x + cos(gl_cam_lr / 180.0 * M_PI), gl_cam_y + sin(gl_cam_ud / 180.0 * M_PI), gl_cam_z + sin(gl_cam_lr / 180.0 * M_PI), 0, 1, 0); + glGetDoublev(GL_MODELVIEW_MATRIX, &modelview2[0]); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glTranslated(0.5, 0.5, 0.5); + glScaled(0.5, 0.5, 0.5); + glMultMatrixd(modelview); + glMultMatrixd(modelview2); + + glMatrixMode(GL_MODELVIEW); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, shadow_texture); + glEnable(GL_TEXTURE_2D); + glActiveTexture(GL_TEXTURE0); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0, GL_POSITION, lightpos); - if(gl_scenes[gl_scene].draw != NULL) gl_scenes[gl_scene].draw(); + scene(); + + glActiveTexture(GL_TEXTURE1); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + + glUseProgram(0); + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + glMatrixMode(GL_MODELVIEW); gl_common(); + + glUseProgram(shadow); + + if(gl_scenes[gl_scene].after != NULL) gl_scenes[gl_scene].after(); } void gl_scene_change(void) { diff --git a/client/gl_main.c b/client/gl_main.c index 59e2827..99f79ae 100644 --- a/client/gl_main.c +++ b/client/gl_main.c @@ -45,5 +45,16 @@ void gl_main_draw(void) { glPopMatrix(); + glColor3f(1, 1, 1); + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-5, -1, -5); + glVertex3f(-5, -1, 5); + glVertex3f(5, -1, 5); + glVertex3f(5, -1, -5); + glEnd(); +} + +void gl_main_after(void) { rad += 60.0 / (1000.0 / AF_WAIT_MS); } diff --git a/client/gl_shader.c b/client/gl_shader.c new file mode 100644 index 0000000..742f76f --- /dev/null +++ b/client/gl_shader.c @@ -0,0 +1,88 @@ +#include + +int gl_shader(GLuint* r, const char* vs, const char* fs) { + GLuint vsi; + GLuint fsi; + FILE* f; + int vsl = 0; + int fsl = 0; + char* vss; + char* fss; + GLint st; + + if((f = fopen(vs, "rb")) != NULL) { + fseek(f, 0, SEEK_END); + vsl = ftell(f); + fseek(f, 0, SEEK_SET); + + vss = malloc(vsl + 1); + fread(vss, vsl, 1, f); + vss[vsl] = 0; + + fclose(f); + } else { + return 0; + } + + if((f = fopen(fs, "rb")) != NULL) { + fseek(f, 0, SEEK_END); + fsl = ftell(f); + fseek(f, 0, SEEK_SET); + + fss = malloc(fsl + 1); + fread(fss, fsl, 1, f); + fss[fsl] = 0; + + fclose(f); + } else { + free(vss); + + return 0; + } + + vsi = glCreateShader(GL_VERTEX_SHADER); + fsi = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(vsi, 1, (const GLchar**)&vss, NULL); + glShaderSource(fsi, 1, (const GLchar**)&fss, NULL); + + glCompileShader(vsi); + glGetShaderiv(vsi, GL_COMPILE_STATUS, &st); + if(!st) { + glDeleteShader(vsi); + glDeleteShader(fsi); + free(vss); + free(fss); + return 0; + } + + glCompileShader(fsi); + glGetShaderiv(fsi, GL_COMPILE_STATUS, &st); + if(!st) { + glDeleteShader(vsi); + glDeleteShader(fsi); + free(vss); + free(fss); + return 0; + } + + free(vss); + free(fss); + + *r = glCreateProgram(); + + glAttachShader(*r, vsi); + glAttachShader(*r, fsi); + + glDeleteShader(vsi); + glDeleteShader(fsi); + + glLinkProgram(*r); + glGetProgramiv(*r, GL_LINK_STATUS, &st); + if(!st) { + glDeleteProgram(*r); + return 0; + } + + return 1; +} diff --git a/include/af_client.h b/include/af_client.h index 237bdbf..22ef027 100644 --- a/include/af_client.h +++ b/include/af_client.h @@ -24,6 +24,7 @@ typedef struct gl_scene { void (*changed)(void); void (*init)(void); void (*draw)(void); + void (*after)(void); } gl_scene_t; extern int gl_scene; @@ -52,6 +53,10 @@ int gl_font_height(const char* text); void gl_main_changed(void); void gl_main_init(void); void gl_main_draw(void); +void gl_main_after(void); + +/* gl_shader.c */ +int gl_shader(GLuint* r, const char* vs, const char* fs); /* net.c */ void net_connect(const char* username, const char* hostname, int port); diff --git a/resource/shadow.fs b/resource/shadow.fs new file mode 100644 index 0000000..5a8ab62 --- /dev/null +++ b/resource/shadow.fs @@ -0,0 +1,8 @@ +#version 110 + +uniform sampler2DShadow texture; +varying vec4 shadow; + +void main (void){ + gl_FragColor = shadow + (gl_Color - shadow) * shadow2DProj(texture, gl_TexCoord[0]); +} diff --git a/resource/shadow.vs b/resource/shadow.vs new file mode 100644 index 0000000..7777bfa --- /dev/null +++ b/resource/shadow.vs @@ -0,0 +1,24 @@ +#version 110 + +varying vec4 shadow; + +void main(void){ + vec3 position = vec3(gl_ModelViewMatrix * gl_Vertex); + vec3 normal = normalize(gl_NormalMatrix * gl_Normal); + vec3 light = normalize(gl_LightSource[0].position.xyz - position); + float diffuse = dot(light, normal); + + gl_FrontColor = gl_LightSource[0].ambient * gl_Color; + shadow = gl_FrontColor; + if (diffuse > 0.0){ + vec3 view = normalize(position); + vec3 halfway = normalize(light - view); + float specular = pow(max(dot(normal, halfway), 0.0), gl_FrontMaterial.shininess); + vec4 temp = gl_LightSource[0].diffuse * gl_Color * diffuse; + shadow += temp * 0.2; + gl_FrontColor += temp + gl_FrontLightProduct[0].specular * specular; + } + + gl_TexCoord[0] = gl_TextureMatrix[0] * gl_ModelViewMatrix * gl_Vertex; + gl_Position = ftransform(); +}