/* This file is part of Iceball. Iceball 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. Iceball 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 Iceball. If not, see . */ #include "common.h" const GLfloat mtx_baseproj[16] = { -1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1, 1, 0, 0,-0.1, 0, }; const GLfloat vfinf_cube[3*6] = { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, }; #if 0 #define DEBUG_INVERT_DRAW_DIR #endif #if 0 #define DEBUG_SHOW_TOP_BOTTOM #define DEBUG_HIDE_MAIN #endif #define CUBESUX_MARKER 20 #define RAYC_MAX ((int)((FOG_MAX_DISTANCE+1)*(FOG_MAX_DISTANCE+1)*8+10)) #define DF_NX 0x01 #define DF_NY 0x02 #define DF_NZ 0x04 #define DF_PX 0x08 #define DF_PY 0x10 #define DF_PZ 0x20 #define DF_SPREAD 0x3F enum { CM_NX = 0, CM_NY, CM_NZ, CM_PX, CM_PY, CM_PZ, CM_MAX }; int cam_shading_map[6][4] = { {CM_PZ, CM_NZ, CM_PY, CM_NY}, {CM_NX, CM_PX, CM_NZ, CM_PZ}, {CM_NX, CM_PX, CM_PY, CM_NY}, {CM_NZ, CM_PZ, CM_PY, CM_NY}, {CM_PX, CM_NX, CM_PZ, CM_NZ}, {CM_PX, CM_NX, CM_PY, CM_NY}, }; float fog_distance = FOG_INIT_DISTANCE; uint32_t fog_color = 0xD0E0FF; uint32_t cam_shading[6] = { 0x000C0, 0x000A0, 0x000D0, 0x000E0, 0x00FF, 0x000D0, }; void render_pillar(map_t *map, map_chunk_t *chunk, int x, int z); /* * REFERENCE IMPLEMENTATION * */ /* custom mod function that handles negative numbers */ inline int render_mod ( int x , int y ) { return x >= 0 ? x % y : y - 1 - ((-x-1) % y) ; } uint32_t render_shade(uint32_t color, int face) { uint32_t fc = cam_shading[face]; return (((((color&0x00FF00FF)*fc)>>8)&0x00FF00FF)) |((((((color>>8)&0x00FF00FF)*fc))&0xFF00FF00))|0x01000000; } GLfloat render_darken_color(GLfloat original_color, GLfloat factor) { return original_color + (factor * (0.0f - original_color)) / 1.0f; } int render_map_get_block_at(map_t *map, int x, int y, int z) { int i; uint8_t *data = NULL; if (map == NULL) return 0; if (y < 0) return 0; data = map->pillars[(z&(map->zlen-1))*(map->xlen)+(x&(map->xlen-1))]; data += 4; for(;;) { if (y>=data[1] && y<=data[2]) return 1; if (y>=data[3] && yvisible_chunks_len + x; } void render_untesselate_visible_chunk(map_chunk_t *chunk) { if (chunk == NULL) return; if (chunk->vbo_arr != NULL) { free(chunk->vbo_arr); chunk->vbo_arr = NULL; } if (chunk->vbo != 0) { glDeleteBuffers(1, &(chunk->vbo)); chunk->vbo = 0; } chunk->vbo_dirty = 0; chunk->vbo_arr_len = 0; } void render_free_visible_chunk(map_chunk_t *chunk) { if (chunk == NULL) return; render_untesselate_visible_chunk(chunk); chunk->cx = 0; chunk->cz = 0; } void render_free_visible_chunks(map_t *map) { int x, z; if(map == NULL || map->visible_chunks_arr == NULL) return; for (x = 0; x < (int) map->visible_chunks_len; x++) { for (z = 0; z < (int) map->visible_chunks_len; z++) { render_free_visible_chunk(&map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]); } } } void render_init_visible_chunks(map_t *map, int starting_chunk_coordinate_x, int starting_chunk_coordinate_z) { /* example for gl_visible_chunks = 9 - array size would be 3x3 - virtual center of the circular array would be [1,1] at init 0 1 2 +---+---+---+ 0 | | | | +---#####---+ 1 | # # | +---#####---+ 2 | | | | +---+---+---+ */ int x, z; /* chunk coordinates */ int cx, cz; if (map == NULL) return; if (map->visible_chunks_arr != NULL) { render_free_visible_chunks(map); free(map->visible_chunks_arr); map->visible_chunks_arr = NULL; } map->visible_chunks_len = ((((int)fog_distance)+(gl_chunk_size+1)/2)/gl_chunk_size)*2+1; map->visible_chunks_arr = (map_chunk_t *) malloc(map->visible_chunks_len * map->visible_chunks_len * sizeof(map_chunk_t)); /* check if the visible chunks array has been allocated properly */ if(map->visible_chunks_arr == NULL) { fprintf(stderr, "render_init_visible_chunks: could not allocate visible chunks array\n"); return; } map->visible_chunks_vcenter_cx = starting_chunk_coordinate_x; map->visible_chunks_vcenter_cz = starting_chunk_coordinate_z; for (x = 0; x < (int) map->visible_chunks_len; x++) { for (z = 0; z < (int) map->visible_chunks_len; z++) { cx = starting_chunk_coordinate_x - (int) map->visible_chunks_len/2 + x; cz = starting_chunk_coordinate_z - (int) map->visible_chunks_len/2 + z; map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].cx = cx; map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].cz = cz; map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].vbo = 0; map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].vbo_dirty = 1; map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].vbo_arr_len = 0; map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].vbo_arr = NULL; } } map->visible_chunks_vcenter_x = (int) map->visible_chunks_len/2; map->visible_chunks_vcenter_z = (int) map->visible_chunks_len/2; } void render_shift_visible_chunks(map_t *map, int camera_chunk_coordinate_x, int camera_chunk_coordinate_z) { int position_shift_x, position_shift_z; int offset_x, offset_z; int index_x, index_z; int x, z; if(map == NULL || map->visible_chunks_arr == NULL) return; position_shift_x = camera_chunk_coordinate_x - map->visible_chunks_vcenter_cx; position_shift_z = camera_chunk_coordinate_z - map->visible_chunks_vcenter_cz; /* if position is the same, nothing to do */ if (position_shift_x == 0 && position_shift_z == 0) return; /* setting the new virtual center of the circular array */ map->visible_chunks_vcenter_x = render_mod(map->visible_chunks_vcenter_x + position_shift_x, (int) map->visible_chunks_len); map->visible_chunks_vcenter_z = render_mod(map->visible_chunks_vcenter_z + position_shift_z, (int) map->visible_chunks_len); /* setting the chunk coordinates of the virtual center of the circular array */ map->visible_chunks_vcenter_cx = camera_chunk_coordinate_x; map->visible_chunks_vcenter_cz = camera_chunk_coordinate_z; for (x = 0; x < (int) map->visible_chunks_len; x++) { for (z = 0; z < (int) map->visible_chunks_len; z++) { offset_x = x - ((int) map->visible_chunks_len- 1)/2; offset_z = z - ((int) map->visible_chunks_len- 1)/2; index_x = render_mod(map->visible_chunks_vcenter_x + offset_x, (int) map->visible_chunks_len); index_z = render_mod(map->visible_chunks_vcenter_z + offset_z, (int) map->visible_chunks_len); /* untesselate chunks not visible anymore */ if (map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)].cx != map->visible_chunks_vcenter_cx + offset_x || map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)].cz != map->visible_chunks_vcenter_cz + offset_z) { render_free_visible_chunk(&map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)]); } /* add chunks that are visible */ if (map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)].vbo_arr == NULL) { map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)].cx = map->visible_chunks_vcenter_cx + offset_x; map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)].cz = map->visible_chunks_vcenter_cz + offset_z; map->visible_chunks_arr[render_visible_chunks_array_offset(map, index_x, index_z)].vbo_dirty = 1; } } } } void render_map_visible_chunks_draw(map_t *map, float fx, float fy, float fz, float cx, float cy, float cz) { int x, z; if(map == NULL || map->visible_chunks_arr == NULL) return; float normfy = fy / sqrtf(fx*fx + fy*fy + fz*fz); float emax = 0.7f * sqrtf(1.0 - normfy*normfy); for (x = 0; x < (int) map->visible_chunks_len; x++) { for (z = 0; z < (int) map->visible_chunks_len; z++) { map_chunk_t *chunk = &(map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]); if (chunk->vbo_arr_len > 0) { if(gl_frustum_cull) { // calculate first corner float px00 = chunk->cx*gl_chunk_size - cx; float pz00 = chunk->cz*gl_chunk_size - cz; // calculate subsequent corners float px01 = px00 + gl_chunk_size; float pz01 = pz00; float px10 = px00; float pz10 = pz00 + gl_chunk_size; float px11 = px01; float pz11 = pz01 + gl_chunk_size; //printf("%f %f -> %f %f\n", px00, pz00, px11, pz11); // get lengths of corners float d00 = sqrtf(px00 * px00 + pz00 * pz00); float d10 = sqrtf(px10 * px10 + pz10 * pz10); float d01 = sqrtf(px01 * px01 + pz01 * pz01); float d11 = sqrtf(px11 * px11 + pz11 * pz11); // normalise corners px00 /= d00; pz00 /= d00; px10 /= d10; pz10 /= d10; px01 /= d01; pz01 /= d01; px11 /= d11; pz11 /= d11; // get normalised 2D forward vector float f2d = sqrtf(fx*fx + fz*fz); float f2x = fx/f2d; float f2z = fz/f2d; // get dot products against forward vector float e00 = px00 * f2x + pz00 * f2z; float e10 = px10 * f2x + pz10 * f2z; float e01 = px01 * f2x + pz01 * f2z; float e11 = px11 * f2x + pz11 * f2z; // frustum cull provided chunk isn't TOO close if(d00/2 >= gl_chunk_size && d01/2 >= gl_chunk_size && d10/2 >= gl_chunk_size && d11/2 >= gl_chunk_size) if(e00 < emax && e01 < emax && e10 < emax && e11 < emax) continue; } // select pointers if (chunk->vbo == 0) { glVertexPointer(3, GL_FLOAT, sizeof(float)*6, chunk->vbo_arr); glColorPointer(3, GL_FLOAT, sizeof(float)*6, chunk->vbo_arr+3); } else { glBindBuffer(GL_ARRAY_BUFFER, chunk->vbo); glVertexPointer(3, GL_FLOAT, sizeof(float)*6, (void *)(0)); glColorPointer(3, GL_FLOAT, sizeof(float)*6, (void *)(0 + sizeof(float)*3)); } // draw glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glDrawArrays(GL_QUADS, 0, chunk->vbo_arr_len); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); // unbind buffer if (chunk->vbo != 0) glBindBuffer(GL_ARRAY_BUFFER, 0); } } } } int render_map_visible_chunks_count_dirty(map_t *map) { int x, z; int dirty_chunks_count = 0; if(map == NULL || map->visible_chunks_arr == NULL) return 0; for (x = 0; x < (int) map->visible_chunks_len; x++) { for (z = 0; z < (int) map->visible_chunks_len; z++) { if (map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].vbo_dirty) { dirty_chunks_count++; } } } return dirty_chunks_count; } void render_map_tesselate_visible_chunks(map_t *map, int camx, int camz) { int x, z, i, vx, vz; int bx, bz; /* pillar coords */ int px, pz; map_chunk_t *chunk; int chunks_tesselated = 0; if(map == NULL || map->visible_chunks_arr == NULL) return; bx = bz = 0; vx = 1; vz = 0; for(i = 0; i < map->visible_chunks_len * map->visible_chunks_len; i++) { x = render_mod(bx + camx + map->visible_chunks_len/2, map->visible_chunks_len); z = render_mod(bz + camz + map->visible_chunks_len/2, map->visible_chunks_len); chunk = &map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]; if (chunks_tesselated >= gl_chunks_tesselated_per_frame) return; if (chunk->vbo_dirty) { render_untesselate_visible_chunk(chunk); for (px = 0; px < gl_chunk_size; px++) { for (pz = 0; pz < gl_chunk_size; pz++) { render_pillar(map, chunk, chunk->cx * gl_chunk_size + px, chunk->cz * gl_chunk_size + pz); } } if(chunk->vbo == 0 && GL_ARB_vertex_buffer_object && gl_use_vbo) glGenBuffers(1, &(chunk->vbo)); if(chunk->vbo != 0) { glBindBuffer(GL_ARRAY_BUFFER, chunk->vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*6*chunk->vbo_arr_len, chunk->vbo_arr, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } chunk->vbo_dirty = 0; chunks_tesselated++; } // rotate around in a spiral bx += vx; bz += vz; if(vz == 0 ? (vx == 1 ? bx > bz : bx <= bz ) : (vz == 1 ? bz >= -bx : bz <= -bx )) { int t = vx; vx = vz; vz = -t; } } } void render_map_mark_chunks_as_dirty(map_t *map, int pillar_x, int pillar_z) { int x, z; int chunk_x, chunk_z; int neighbor_chunk_x, neighbor_chunk_z; map_chunk_t *neighbor_chunk = NULL; chunk_x = pillar_x/gl_chunk_size; chunk_z = pillar_z/gl_chunk_size; if(map == NULL || map->visible_chunks_arr == NULL) return; for (x = 0; x < (int) map->visible_chunks_len; x++) { for (z = 0; z < (int) map->visible_chunks_len; z++) { if (map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].cx == chunk_x && map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].cz == chunk_z) { map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)].vbo_dirty = 1; /* If pillar coords are between two chunks, we need to update the neighbor chunks as well */ if (render_mod(pillar_x, gl_chunk_size) == 0) { neighbor_chunk_x = render_mod(x - 1, (int) map->visible_chunks_len); neighbor_chunk_z = z; neighbor_chunk = &map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]; if (neighbor_chunk->cx == chunk_x - 1 && neighbor_chunk->cz == chunk_z) { neighbor_chunk->vbo_dirty = 1; } } else if (render_mod(pillar_x, gl_chunk_size) == gl_chunk_size-1) { neighbor_chunk_x = render_mod(x + 1, (int) map->visible_chunks_len); neighbor_chunk_z = z; neighbor_chunk = &map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]; if (neighbor_chunk->cx == chunk_x + 1 && neighbor_chunk->cz == chunk_z) { neighbor_chunk->vbo_dirty = 1; } } if (render_mod(pillar_z, gl_chunk_size) == 0) { neighbor_chunk_x = x; neighbor_chunk_z = render_mod(z - 1, (int) map->visible_chunks_len); neighbor_chunk = &map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]; if (neighbor_chunk->cx == chunk_x && neighbor_chunk->cz == chunk_z - 1) { neighbor_chunk->vbo_dirty = 1; } } else if (render_mod(pillar_z, gl_chunk_size) == gl_chunk_size-1) { neighbor_chunk_x = x; neighbor_chunk_z = render_mod(z + 1, (int) map->visible_chunks_len); neighbor_chunk = &map->visible_chunks_arr[render_visible_chunks_array_offset(map, x, z)]; if (neighbor_chunk->cx == chunk_x && neighbor_chunk->cz == chunk_z + 1) { neighbor_chunk->vbo_dirty = 1; } } return; } } } } void render_update_vbo(float **arr, int *len, int *max, int newlen) { int xlen = 0; if(*arr == NULL) { xlen = newlen + 10; } else if(newlen <= *max) { return; } else { xlen = ((*max)*3)/2+1; if(xlen < newlen) xlen = newlen + 10; } *arr = (float*)realloc(*arr, xlen*sizeof(float)*6); *max = xlen; } void render_gl_cube_pmf(model_bone_t *bone, float x, float y, float z, float r, float g, float b, float rad) { int i; float ua,ub,uc; float va,vb,vc; render_update_vbo(&(bone->vbo_arr), &(bone->vbo_arr_len), &(bone->vbo_arr_max), bone->vbo_arr_len+4*6); float *arr = bone->vbo_arr; arr += bone->vbo_arr_len*6; bone->vbo_arr_len += 4*6; for(i = 0; i < 3; i++) { float s2 = ((int)cam_shading[i+0])/255.0f; float s1 = ((int)cam_shading[i+3])/255.0f; float cr,cg,cb; ua = vfinf_cube[i*6+0]; ub = vfinf_cube[i*6+1]; uc = vfinf_cube[i*6+2]; va = vfinf_cube[i*6+3]; vb = vfinf_cube[i*6+4]; vc = vfinf_cube[i*6+5]; #define ARR_ADD(vx,vy,vz) \ *(arr++) = vx; *(arr++) = vy; *(arr++) = vz; \ *(arr++) = cr; *(arr++) = cg; *(arr++) = cb; /* Quad 1 */ cr = r*s1; cg = g*s1, cb = b*s1; ARR_ADD(x,y,z); ARR_ADD(x+rad*ua,y+rad*ub,z+rad*uc); ARR_ADD(x+rad*(ua+va),y+rad*(ub+vb),z+rad*(uc+vc)); ARR_ADD(x+rad*va,y+rad*vb,z+rad*vc); /* Quad 2 */ cr = r*s2; cg = g*s2, cb = b*s2; ARR_ADD(x+rad,y+rad,z+rad); ARR_ADD(x+rad*(1-va),y+rad*(1-vb),z+rad*(1-vc)); ARR_ADD(x+rad*(1-ua-va),y+rad*(1-ub-vb),z+rad*(1-uc-vc)); ARR_ADD(x+rad*(1-ua),y+rad*(1-ub),z+rad*(1-uc)); #undef ARR_ADD } } void render_gl_cube_map(map_t *map, map_chunk_t *chunk, float x, float y, float z, float r, float g, float b, float rad) { int i; float ua,ub,uc; float va,vb,vc; float average_light_vertex1, average_light_vertex2, average_light_vertex3, average_light_vertex4; float *arr = chunk->vbo_arr; /* Quads rendering explained (sort of) 'o' in drawings represents the vertex at origin '+' a vertex '1' digits represents vertex number i = 0 | i = 1 | i = 2 ----- | ----- | ----- | | Quad 1 (left) Quad 2 (right) | Quad 1 (top) Quad 2 (bottom) | Quad 1 (back) Quad 2 (front) | | 1 3 | 1 4 | 1 2 +-- x o....... o......+ | +-- x o------+ o....... | +-- x o------+ o....... /| 4 /| .. .. 4 /| | /| /. /. .. .. | /| .| .| 3 .. 2. z y +.|..... . .......+ | |z y +------+ . ........ . |z y ..|..... | +------+ . | +....... . .....|.+ | 2. ......3. . +------+ | . +------+ | .....|.. |/ 2 .. .. |/ 2 | .. .. ./ 3 ./ 4 | .. 4 .. 3 |. |/ +....... .......+ | ........ +------+ | ........ +------+ 3 1 | 2 1 | 4 1 | | ua = 0.0 va = 0.0 | ua = 0.0 va = 1.0 | ua = 1.0 va = 0.0 ub = 1.0 vb = 0.0 | ub = 0.0 vb = 0.0 | ub = 0.0 vb = 1.0 uc = 0.0 vc = 1.0 | uc = 1.0 vc = 0.0 | uc = 0.0 vc = 0.0 | | | | Neighbor to check for face drawing toggle | Neighbor to check for face drawing toggle | Neighbor to check for face drawing toggle | | Quad1 Quad2 | Quad1 Quad2 | Quad1 Quad2 x - 1 x + 1 | y - 1 y + 1 | z - 1 z + 1 | | | | Neighbors to check for light average | Neighbors to check for light average | Neighbors to check for light average | | Left Right | Top Bottom | Back Front ---- ----- | ------ --- | ---- ----- | | Vertex1 Vertex1 | Vertex1 Vertex1 | Vertex1 Vertex1 x-1, y, z x+1, y, z | x, y-1, z x, y+1, z | x, y, z-1 x, y, z+1 x-1, y-1, z x+1, y+1, z | x-1, y-1, z x+1, y+1, z | x-1, y, z-1 x+1, y, z+1 x-1, y-1, z-1 x+1, y+1, z+1 | x-1, y-1, z-1 x+1 y+1, z+1 | x-1, y-1, z-1 x+1, y+1, z+1 x-1, y, z-1 x+1, y, z+1 | x, y-1, z-1 x, y+1, z+1 | x, y-1, z-1 x, y+1, z+1 | | Vertex2 Vertex2 | Vertex2 Vertex2 | Vertex2 Vertex2 x-1, y, z x+1, y, z | x, y-1, z x, y+1, z | x, y, z-1 x, y, z+1 x-1, y+1, z x+1, y+1, z | x-1, y-1, z x-1, y+1, z | x+1, y, z-1 x+1, y, z+1 x-1, y+1, z-1 x+1, y+1, z-1 | x-1, y-1, z+1 x-1, y+1, z+1 | x+1, y-1, z-1 x+1, y-1, z+1 x-1, y, z-1 x+1, y, z-1 | x, y-1, z+1 x, y+1, z+1 | x, y-1, z-1 x, y-1, z+1 | | Vertex3 Vertex3 | Vertex3 Vertex3 | Vertex3 Vertex3 x-1, y, z x+1, y, z | x, y-1, z x, y+1, z | x, y, z-1 x, y, z+1 x-1, y+1, z x+1, y-1, z | x+1, y-1, z x-1, y+1, z | x+1, y, z-1 x-1, y, z+1 x-1, y+1, z+1 x+1, y-1, z-1 | x+1, y-1, z+1 x-1, y+1, z-1 | x+1, y+1, z-1 x-1, y-1, z+1 x-1, y, z+1 x+1, y, z-1 | x, y-1, z+1 x, y+1, z-1 | x, y+1, z-1 x, y-1, z+1 | | Vertex4 Vertex4 | Vertex4 Vertex4 | Vertex4 Vertex4 x-1, y, z x+1, y, z | x, y-1, z x, y+1 z | x, y, z-1 x, y, z+1 x-1, y-1, z x+1, y-1, z | x+1, y-1, z x+1, y+1 z | x-1, y, z-1 x-1, y, z+1 x-1, y-1, z+1 x+1, y-1, z+1 | x+1, y-1, z-1 x+1, y+1 z-1 | x-1, y+1, z-1 x-1, y+1, z+1 x-1, y , z+1 x+1, y, z+1 | x, y-1, z-1 x, y+1 z-1 | x, y+1, z-1 x, y+1, z+1 Neighbors to check for face drawing : Quad 1 Quad 2 ------ ------ x - ub, y - uc, z - ua x + vc, y + va, z + vb Generic coordinates formula (<=> regardless of i value) to check for each vertex (holy moly, it seems to be working ^^) : Quad 1 Quad 2 ------ ------ V1 V1 x-ub, y-uc, z-ua x+vc, y+va, z+vb x-1, y-1+ua, z-ua x+1, y+1-vb, z+vb x-1, y-1, z-1 x+1, y+1, z+1 x-ub, y-1+ub, z-1 x+vc, y+1-vc, z+1 V2 V2 x-ub, y-uc, z-ua x+vc, y+va, z+vb x-1+2*ua, y+(1-ua)-2*uc, z-ua x+1-2*va, y+1-vb, z+vb x-1+2*ua, y-1+2*ub, z-1+2*uc x+1-2*va, y+1-2*vb, z+1-2*vc x-ub, y-1+ub, z-1+2*uc x+vc, y+(1-vc)-2*vb, z+1-2*vc V3 V3 x-ub, y-uc, z-ua x+vc, y+va, z+vb x+1-2*ub, y+(1-ua)-2*uc, z-ua x-1+2*vc, y+(1-vb)-2*vc, z+vb x+1-2*ub, y+1-2*uc, z+1-2*ua x-1+2*vc, y-1+2*va, z-1+2*vb x-ub, y+(1-ub)-2*uc, z+1-2*ua x+vc, y+(1-vc)-2*vb, z-1+2*vb V4 V4 x-ub, y-uc, z-ua x+vc, y+va, z+vb x-1+2*uc, y-1+ua, z-ua x+1-2*vb, y+(1-vb)-2*vc, z+vb x-1+2*uc, y-1+2*ua, z-1+2*ub x+1-2*vb, y+1-2*vc, z+1-2*va x-ub, y+(1-ub)-2*uc, z-1+2*ub x+vc, y+1-vc, z+1-2*va */ for(i = 0; i < 3; i++) { ua = vfinf_cube[i*6+0]; ub = vfinf_cube[i*6+1]; uc = vfinf_cube[i*6+2]; va = vfinf_cube[i*6+3]; vb = vfinf_cube[i*6+4]; vc = vfinf_cube[i*6+5]; float s2 = ((int)cam_shading[i+0])/255.0f; float s1 = ((int)cam_shading[i+3])/255.0f; float cr,cg,cb; #define ARR_ADD(vx,vy,vz) \ *(arr++) = vx; *(arr++) = vy; *(arr++) = vz; \ *(arr++) = cr; *(arr++) = cg; *(arr++) = cb; /* check visibility of the face (is face exposed to air ?) */ if (render_map_get_block_at(map, x - ub, y - uc, z - ua) == 0) { render_update_vbo(&(chunk->vbo_arr), &(chunk->vbo_arr_len), &(chunk->vbo_arr_max), chunk->vbo_arr_len+4); arr = chunk->vbo_arr; arr += chunk->vbo_arr_len*6; chunk->vbo_arr_len += 4; if (screen_smooth_lighting) { average_light_vertex1 = render_get_average_light( map, x-ub, y-uc, z-ua, x-1, y-1+ua, z-ua, x-1, y-1, z-1, x-ub, y-1+ub, z-1); average_light_vertex2 = render_get_average_light( map, x-ub, y-uc, z-ua, x-1+2*ua, y+(1-ua)-2*uc, z-ua, x-1+2*ua, y-1+2*ub, z-1+2*uc, x-ub, y-1+ub, z-1+2*uc); average_light_vertex3 = render_get_average_light( map, x-ub, y-uc, z-ua, x+1-2*ub, y+(1-ua)-2*uc, z-ua, x+1-2*ub, y+1-2*uc, z+1-2*ua, x-ub, y+(1-ub)-2*uc, z+1-2*ua); average_light_vertex4 = render_get_average_light( map, x-ub, y-uc, z-ua, x-1+2*uc, y-1+ua, z-ua, x-1+2*uc, y-1+2*ua, z-1+2*ub, x-ub, y+(1-ub)-2*uc, z-1+2*ub); } else { average_light_vertex1 = 0.0f; average_light_vertex2 = 0.0f; average_light_vertex3 = 0.0f; average_light_vertex4 = 0.0f; } /* Check if the quad needs to be rotated (fix for ambient occlusion on sides) */ if (average_light_vertex1 + average_light_vertex3 > average_light_vertex2 + average_light_vertex4) { /* Quad 1 rotated */ /* vertex 2 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex2); cg = render_darken_color(cg, average_light_vertex2); cb = render_darken_color(cb, average_light_vertex2); ARR_ADD(x+rad*ua,y+rad*ub,z+rad*uc); /* vertex 3 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex3); cg = render_darken_color(cg, average_light_vertex3); cb = render_darken_color(cb, average_light_vertex3); ARR_ADD(x+rad*(ua+va),y+rad*(ub+vb),z+rad*(uc+vc)); /* vertex 4 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex4); cg = render_darken_color(cg, average_light_vertex4); cb = render_darken_color(cb, average_light_vertex4); ARR_ADD(x+rad*va,y+rad*vb,z+rad*vc); /* vertex 1 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex1); cg = render_darken_color(cg, average_light_vertex1); cb = render_darken_color(cb, average_light_vertex1); ARR_ADD(x,y,z); } else { /* Quad 1 normal */ /* vertex 1 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex1); cg = render_darken_color(cg, average_light_vertex1); cb = render_darken_color(cb, average_light_vertex1); ARR_ADD(x,y,z); /* vertex 2 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex2); cg = render_darken_color(cg, average_light_vertex2); cb = render_darken_color(cb, average_light_vertex2); ARR_ADD(x+rad*ua,y+rad*ub,z+rad*uc); /* vertex 3 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex3); cg = render_darken_color(cg, average_light_vertex3); cb = render_darken_color(cb, average_light_vertex3); ARR_ADD(x+rad*(ua+va),y+rad*(ub+vb),z+rad*(uc+vc)); /* vertex 4 */ cr = r*s1; cg = g*s1, cb = b*s1; cr = render_darken_color(cr, average_light_vertex4); cg = render_darken_color(cg, average_light_vertex4); cb = render_darken_color(cb, average_light_vertex4); ARR_ADD(x+rad*va,y+rad*vb,z+rad*vc); } } /* check visibility of the face (is face exposed to air ?) */ if (render_map_get_block_at(map, x + vc, y + va, z + vb) == 0) { render_update_vbo(&(chunk->vbo_arr), &(chunk->vbo_arr_len), &(chunk->vbo_arr_max), chunk->vbo_arr_len+4); arr = chunk->vbo_arr; arr += chunk->vbo_arr_len*6; chunk->vbo_arr_len += 4; if (screen_smooth_lighting) { average_light_vertex1 = render_get_average_light( map, x+vc, y+va, z+vb, x+1, y+1-vb, z+vb, x+1, y+1, z+1, x+vc, y+1-vc, z+1); average_light_vertex2 = render_get_average_light( map, x+vc, y+va, z+vb, x+1-2*va, y+1-vb, z+vb, x+1-2*va, y+1-2*vb, z+1-2*vc, x+vc, y+(1-vc)-2*vb, z+1-2*vc); average_light_vertex3 = render_get_average_light( map, x+vc, y+va, z+vb, x-1+2*vc, y+(1-vb)-2*vc, z+vb, x-1+2*vc, y-1+2*va, z-1+2*vb, x+vc, y+(1-vc)-2*vb, z-1+2*vb); average_light_vertex4 = render_get_average_light( map, x+vc, y+va, z+vb, x+1-2*vb, y+(1-vb)-2*vc, z+vb, x+1-2*vb, y+1-2*vc, z+1-2*va, x+vc, y+1-vc, z+1-2*va); } else { average_light_vertex1 = 0.0f; average_light_vertex2 = 0.0f; average_light_vertex3 = 0.0f; average_light_vertex4 = 0.0f; } /* Check if the quad needs to be rotated (fix for ambient occlusion on sides) */ if (average_light_vertex1 + average_light_vertex3 > average_light_vertex2 + average_light_vertex4) { /* Quad 2 rotated */ /* vertex 2 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex2); cg = render_darken_color(cg, average_light_vertex2); cb = render_darken_color(cb, average_light_vertex2); ARR_ADD(x+rad*(1-va),y+rad*(1-vb),z+rad*(1-vc)); /* vertex 3 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex3); cg = render_darken_color(cg, average_light_vertex3); cb = render_darken_color(cb, average_light_vertex3); ARR_ADD(x+rad*(1-ua-va),y+rad*(1-ub-vb),z+rad*(1-uc-vc)); /* vertex 4 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex4); cg = render_darken_color(cg, average_light_vertex4); cb = render_darken_color(cb, average_light_vertex4); ARR_ADD(x+rad*(1-ua),y+rad*(1-ub),z+rad*(1-uc)); /* vertex 1 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex1); cg = render_darken_color(cg, average_light_vertex1); cb = render_darken_color(cb, average_light_vertex1); ARR_ADD(x+rad,y+rad,z+rad); } else { /* Quad 2 normal */ /* vertex 1 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex1); cg = render_darken_color(cg, average_light_vertex1); cb = render_darken_color(cb, average_light_vertex1); ARR_ADD(x+rad,y+rad,z+rad); /* vertex 2 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex2); cg = render_darken_color(cg, average_light_vertex2); cb = render_darken_color(cb, average_light_vertex2); ARR_ADD(x+rad*(1-va),y+rad*(1-vb),z+rad*(1-vc)); /* vertex 3 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex3); cg = render_darken_color(cg, average_light_vertex3); cb = render_darken_color(cb, average_light_vertex3); ARR_ADD(x+rad*(1-ua-va),y+rad*(1-ub-vb),z+rad*(1-uc-vc)); /* vertex 4 */ cr = r*s2; cg = g*s2, cb = b*s2; cr = render_darken_color(cr, average_light_vertex4); cg = render_darken_color(cg, average_light_vertex4); cb = render_darken_color(cb, average_light_vertex4); ARR_ADD(x+rad*(1-ua),y+rad*(1-ub),z+rad*(1-uc)); } } #undef ARR_ADD } } void render_vxl_cube(map_t *map, map_chunk_t *chunk, int x, int y, int z, uint8_t *color) { render_gl_cube_map(map, chunk, x, y, z, color[2]/255.0f, color[1]/255.0f, color[0]/255.0f, 1); } void render_pmf_cube(model_bone_t *bone, float x, float y, float z, int r, int g, int b, float rad) { float hrad = rad/2.0f; render_gl_cube_pmf(bone, x-hrad, y-hrad, z-hrad, r/255.0f, g/255.0f, b/255.0f, rad); } void render_vxl_redraw(camera_t *camera, map_t *map) { if(map == NULL) return; int x,y,z; int cx,cy,cz; cx = camera->mpx; cy = camera->mpy; cz = camera->mpz; render_shift_visible_chunks(map, cx/gl_chunk_size, cz/gl_chunk_size); render_map_tesselate_visible_chunks(map, cx/gl_chunk_size, cz/gl_chunk_size); } void render_pillar(map_t *map, map_chunk_t *chunk, int x, int z) { int y, i; if(map == NULL || chunk == NULL) return; uint8_t *data = map->pillars[(z&(map->zlen-1))*(map->xlen)+(x&(map->xlen-1))]; data += 4; int lastct = 0; for(;;) { for(y = data[1]; y <= data[2]; y++) render_vxl_cube(map, chunk, x, y, z, &data[4*(y-data[1]+1)]); lastct = -(data[2]-data[1]+1); if(lastct < 0) lastct = 0; lastct += data[0]-1; if(data[0] == 0) break; data += 4*(int)data[0]; for(y = data[3]-lastct; y < data[3]; y++) render_vxl_cube(map, chunk, x, y, z, &data[4*(y-data[3])]); } } void render_cubemap(uint32_t *pixels, int width, int height, int pitch, camera_t *camera, map_t *map) { int x,y,z; float cx,cy,cz; float fog[4] = { ((fog_color>>16)&255)/255.0,((fog_color>>8)&255)/255.0,((fog_color)&255)/255.0,1 }; float cfx,cfy,cfz; cfx = camera->mzx; cfy = camera->mzy; cfz = camera->mzz; float cfd2 = cfx*cfx+cfy*cfy+cfz*cfz; cfd2 = 1.0f/cfd2; glClearColor(fog[0], fog[1], fog[2], 1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glEnable(GL_FOG); glFogi(GL_FOG_MODE, GL_LINEAR); float cdist = fog_distance/sqrtf(2.0f*cfd2); glFogf(GL_FOG_START, cdist/2.0f); glFogf(GL_FOG_END, cdist); glFogfv(GL_FOG_COLOR, fog); cx = camera->mpx; cy = camera->mpy; cz = camera->mpz; GLfloat mtx_mv[16] = { camera->mxx, camera->myx, camera->mzx, 0, camera->mxy, camera->myy, camera->mzy, 0, camera->mxz, camera->myz, camera->mzz, 0, 0,0,0,1 }; glMatrixMode(GL_MODELVIEW); glLoadMatrixf(mtx_mv); glTranslatef(-cx,-cy,-cz); if(map == NULL) return; render_map_visible_chunks_draw(map, cfx, cfy, cfz, cx, cy, cz); } void render_pmf_bone(uint32_t *pixels, int width, int height, int pitch, camera_t *cam_base, model_bone_t *bone, int islocal, float px, float py, float pz, float ry, float rx, float ry2, float scale) { int i; glEnable(GL_DEPTH_TEST); glPushMatrix(); if(islocal) glLoadIdentity(); glTranslatef(px, py, pz); glScalef(scale,scale,scale); glRotatef(ry2*180.0f/M_PI, 0.0f, 1.0f, 0.0f); glRotatef(rx*180.0f/M_PI, 1.0f, 0.0f, 0.0f); glRotatef(ry*180.0f/M_PI, 0.0f, 1.0f, 0.0f); if(bone->vbo_dirty) { bone->vbo_arr_len = 0; for(i = 0; i < bone->ptlen; i++) { float ox, oy, oz; const float oamp = 0.0004; const float oper = 0.031; ox = oamp*sin(i*oper*M_PI*2.0); oy = oamp*sin(i*oper*M_PI*2.0 + M_PI*2.0/3.0); oz = oamp*sin(i*oper*M_PI*2.0 - M_PI*2.0/3.0); model_point_t *pt = &(bone->pts[i]); render_pmf_cube(bone, pt->x/256.0f+ox, pt->y/256.0f+oy, pt->z/256.0f+oz, pt->r, pt->g, pt->b, pt->radius*2.0f/256.0f + oamp); } bone->vbo_dirty = 0; if(bone->vbo == 0 && GL_ARB_vertex_buffer_object && gl_use_vbo) glGenBuffers(1, &(bone->vbo)); if(bone->vbo != 0) { glBindBuffer(GL_ARRAY_BUFFER, bone->vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*6*bone->vbo_arr_len, bone->vbo_arr, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } } if(bone->vbo == 0) { glVertexPointer(3, GL_FLOAT, sizeof(float)*6, bone->vbo_arr); glColorPointer(3, GL_FLOAT, sizeof(float)*6, bone->vbo_arr+3); } else { glBindBuffer(GL_ARRAY_BUFFER, bone->vbo); glVertexPointer(3, GL_FLOAT, sizeof(float)*6, (void *)(0)); glColorPointer(3, GL_FLOAT, sizeof(float)*6, (void *)(0 + sizeof(float)*3)); } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glDrawArrays(GL_QUADS, 0, bone->vbo_arr_len); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); if(bone->vbo != 0) glBindBuffer(GL_ARRAY_BUFFER, 0); glPopMatrix(); } int render_init(int width, int height) { glMatrixMode(GL_PROJECTION); glLoadMatrixf(mtx_baseproj); if(width > height) glScalef(1.0f,((float)width)/((float)height),1.0f); else glScalef(((float)height)/((float)width),1.0f,1.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // probably something. return 0; } void render_deinit(void) { // probably nothing. }