gpuray_glsl
diff src/gpuscene.cc @ 0:f234630e38ff
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 09 Nov 2014 13:03:36 +0200 |
parents | |
children | 2ed3da7dc0bc |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/gpuscene.cc Sun Nov 09 13:03:36 2014 +0200 1.3 @@ -0,0 +1,317 @@ 1.4 +#include <algorithm> 1.5 +#include <assert.h> 1.6 +#include "gpuscene.h" 1.7 +#include "sphere.h" 1.8 +#include "plane.h" 1.9 +#include "box.h" 1.10 +#include "opengl.h" 1.11 + 1.12 +GPUScene::GPUScene() 1.13 +{ 1.14 + glGenTextures(NUM_TEXTURES, textures); 1.15 + 1.16 + for(int i=0; i<NUM_TEXTURES; i++) { 1.17 + glBindTexture(GL_TEXTURE_2D, textures[i]); 1.18 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1.19 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1.20 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 1.21 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 1.22 + } 1.23 + 1.24 + xform_buf = 0; 1.25 +} 1.26 + 1.27 +GPUScene::~GPUScene() 1.28 +{ 1.29 + glDeleteTextures(NUM_TEXTURES, textures); 1.30 + delete [] xform_buf; 1.31 +} 1.32 + 1.33 +bool GPUScene::create_textures() 1.34 +{ 1.35 + // must be first to generate the megatecture rectangles 1.36 + create_megatexture(); 1.37 + 1.38 + Sphere *sph; 1.39 + Plane *plane; 1.40 + Box *box; 1.41 + 1.42 + std::vector<Sphere*> spheres; 1.43 + std::vector<Plane*> planes; 1.44 + std::vector<Box*> boxes; 1.45 + 1.46 + // collect all objects into the different type-specific arrays 1.47 + for(auto obj : objects) { 1.48 + if((sph = dynamic_cast<Sphere*>(obj))) { 1.49 + spheres.push_back(sph); 1.50 + 1.51 + } else if((plane = dynamic_cast<Plane*>(obj))) { 1.52 + planes.push_back(plane); 1.53 + 1.54 + } else if((box = dynamic_cast<Box*>(obj))) { 1.55 + boxes.push_back(box); 1.56 + 1.57 + } else { 1.58 + fprintf(stderr, "skipping object of unknown type: %s\n", obj->get_name()); 1.59 + } 1.60 + } 1.61 + 1.62 + create_sphere_texture(spheres); 1.63 + create_plane_texture(planes); 1.64 + create_box_texture(boxes); 1.65 + 1.66 + create_env_texture(); 1.67 + create_xform_texture(); 1.68 + 1.69 + return true; 1.70 +} 1.71 + 1.72 +unsigned int GPUScene::get_texture(int which) const 1.73 +{ 1.74 + return textures[which]; 1.75 +} 1.76 + 1.77 +#define MAT_START 4 1.78 +static void copy_material(Vector4 *ptr, const Material *mtl) 1.79 +{ 1.80 + ptr[MAT_START].x = mtl->diffuse.x; 1.81 + ptr[MAT_START].y = mtl->diffuse.y; 1.82 + ptr[MAT_START].z = mtl->diffuse.z; 1.83 + ptr[MAT_START].w = mtl->transparency; 1.84 + 1.85 + ptr[MAT_START + 1].x = mtl->specular.x; 1.86 + ptr[MAT_START + 1].y = mtl->specular.y; 1.87 + ptr[MAT_START + 1].z = mtl->specular.z; 1.88 + ptr[MAT_START + 1].w = mtl->shininess; 1.89 + 1.90 + ptr[MAT_START + 2].x = mtl->reflectivity; 1.91 + ptr[MAT_START + 2].y = mtl->ior; 1.92 + 1.93 + ptr[MAT_START + 3] = mtl->mega_rect; 1.94 +} 1.95 + 1.96 +int GPUScene::object_index(const Object *obj) const 1.97 +{ 1.98 + for(int i=0; i<(int)objects.size(); i++) { 1.99 + if(objects[i] == obj) { 1.100 + return i; 1.101 + } 1.102 + } 1.103 + abort(); // can't happen 1.104 + return -1; 1.105 +} 1.106 + 1.107 +#define OBJ_LINE_WIDTH 16 1.108 +void GPUScene::create_sphere_texture(const std::vector<Sphere*> &spheres) 1.109 +{ 1.110 + int xsz = OBJ_LINE_WIDTH; 1.111 + int ysz = (int)spheres.size() + 1; 1.112 + int tex_ysz = next_pow2(ysz); 1.113 + 1.114 + Vector4 *pixels = new Vector4[xsz * tex_ysz]; 1.115 + 1.116 + pixels[0].x = (float)ysz; 1.117 + pixels[0].y = (float)tex_ysz; 1.118 + pixels[0].z = 0.5; 1.119 + pixels[0].w = 1.0; 1.120 + 1.121 + Vector4 *pixptr = pixels + xsz; 1.122 + 1.123 + for(size_t i=0; i<spheres.size(); i++) { 1.124 + pixptr[0].x = object_index(spheres[i]); 1.125 + 1.126 + pixptr[1].x = spheres[i]->pos.x; 1.127 + pixptr[1].y = spheres[i]->pos.y; 1.128 + pixptr[1].z = spheres[i]->pos.z; 1.129 + pixptr[1].w = spheres[i]->radius; 1.130 + 1.131 + copy_material(pixptr, &spheres[i]->material); 1.132 + pixptr += OBJ_LINE_WIDTH; 1.133 + } 1.134 + 1.135 + glBindTexture(GL_TEXTURE_2D, textures[TEX_SPHERE]); 1.136 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels); 1.137 + 1.138 + delete [] pixels; 1.139 +} 1.140 + 1.141 +void GPUScene::create_plane_texture(const std::vector<Plane*> &planes) 1.142 +{ 1.143 + int xsz = OBJ_LINE_WIDTH; 1.144 + int ysz = (int)planes.size() + 1; 1.145 + int tex_ysz = next_pow2(ysz); 1.146 + 1.147 + Vector4 *pixels = new Vector4[xsz * tex_ysz]; 1.148 + 1.149 + pixels[0].x = (float)ysz; 1.150 + pixels[0].y = (float)tex_ysz; 1.151 + 1.152 + Vector4 *pixptr = pixels + xsz; 1.153 + 1.154 + for(size_t i=0; i<planes.size(); i++) { 1.155 + pixptr[0].x = object_index(planes[i]); 1.156 + 1.157 + pixptr[1].x = planes[i]->normal.x; 1.158 + pixptr[1].y = planes[i]->normal.y; 1.159 + pixptr[1].z = planes[i]->normal.z; 1.160 + pixptr[1].w = planes[i]->dist; 1.161 + 1.162 + copy_material(pixptr, &planes[i]->material); 1.163 + pixptr += OBJ_LINE_WIDTH; 1.164 + } 1.165 + 1.166 + glBindTexture(GL_TEXTURE_2D, textures[TEX_PLANE]); 1.167 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels); 1.168 + 1.169 + delete [] pixels; 1.170 +} 1.171 + 1.172 +void GPUScene::create_box_texture(const std::vector<Box*> &boxes) 1.173 +{ 1.174 + int xsz = OBJ_LINE_WIDTH; 1.175 + int ysz = (int)boxes.size() + 1; 1.176 + int tex_ysz = next_pow2(ysz); 1.177 + 1.178 + Vector4 *pixels = new Vector4[xsz * tex_ysz]; 1.179 + 1.180 + pixels[0].x = (float)ysz; 1.181 + pixels[0].y = (float)tex_ysz; 1.182 + 1.183 + Vector4 *pixptr = pixels + xsz; 1.184 + 1.185 + for(size_t i=0; i<boxes.size(); i++) { 1.186 + pixptr[0].x = object_index(boxes[i]); 1.187 + pixptr[1] = boxes[i]->min; 1.188 + pixptr[2] = boxes[i]->max; 1.189 + 1.190 + copy_material(pixptr, &boxes[i]->material); 1.191 + pixptr += OBJ_LINE_WIDTH; 1.192 + } 1.193 + 1.194 + glBindTexture(GL_TEXTURE_2D, textures[TEX_BOX]); 1.195 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels); 1.196 + 1.197 + delete [] pixels; 1.198 +} 1.199 + 1.200 +void GPUScene::create_megatexture() 1.201 +{ 1.202 + // at least a 1x1 dummy white texture 1.203 + int xsz = 1; 1.204 + int ysz = 1; 1.205 + int num_textures = 0; 1.206 + 1.207 + for(auto obj : objects) { 1.208 + // only need 2D textures at this point 1.209 + Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex); 1.210 + if(tex) { 1.211 + const Image *img = tex->get_image(); 1.212 + 1.213 + xsz = std::max(xsz, img->xsz); 1.214 + ysz += img->ysz; 1.215 + num_textures++; 1.216 + } 1.217 + } 1.218 + 1.219 + int tex_xsz = next_pow2(xsz); 1.220 + int tex_ysz = next_pow2(ysz); 1.221 + 1.222 + Color *pixels = new Color[tex_xsz * tex_ysz]; 1.223 + 1.224 + // null texture 1.225 + pixels[0] = Color(1, 1, 1); 1.226 + 1.227 + Color *pixptr = pixels + tex_xsz; 1.228 + 1.229 + float offs_y = 0.0; 1.230 + for(auto obj : objects) { 1.231 + Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex); 1.232 + if(tex) { 1.233 + const Image *img = tex->get_image(); 1.234 + 1.235 + Vector4 rect{0.0, offs_y, (float)img->xsz / (float)tex_xsz, 1.236 + (float)img->ysz / (float)tex_ysz}; 1.237 + 1.238 + offs_y += rect.w; 1.239 + 1.240 + obj->material.mega_rect = rect; 1.241 + 1.242 + for(int i=0; i<img->ysz; i++) { 1.243 + memcpy(pixptr, img->pixels + i * img->xsz, img->xsz * sizeof *pixels); 1.244 + pixptr += tex_xsz; 1.245 + } 1.246 + } else { 1.247 + obj->material.mega_rect = Vector4(0, 0, 0, 0); 1.248 + } 1.249 + } 1.250 + 1.251 + glBindTexture(GL_TEXTURE_2D, textures[TEX_TEXTURE]); 1.252 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, pixels); 1.253 + 1.254 + delete [] pixels; 1.255 +} 1.256 + 1.257 +void GPUScene::create_env_texture() 1.258 +{ 1.259 + // create the scene cubemap, or a null cubemap if we don't have one 1.260 + glDeleteTextures(1, textures + TEX_ENV); // cause it's not a 2D texture :) 1.261 + 1.262 + glGenTextures(1, textures + TEX_ENV); 1.263 + glBindTexture(GL_TEXTURE_CUBE_MAP, textures[TEX_ENV]); 1.264 + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1.265 + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.266 + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1.267 + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1.268 + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 1.269 + 1.270 + if(envmap) { 1.271 + // we have an environment cubemap, just pass the data to OpenGL 1.272 + for(int i=0; i<6; i++) { 1.273 + const Image *img = envmap->get_image(i); 1.274 + 1.275 + int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; 1.276 + glTexImage2D(face, 0, GL_RGB16F, img->xsz, img->ysz, 0, GL_RGB, GL_FLOAT, img->pixels); 1.277 + } 1.278 + } else { 1.279 + // we don't have an env cubemap, make a dummy 1x1 cubemap with the background color 1.280 + for(int i=0; i<6; i++) { 1.281 + int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; 1.282 + glTexImage2D(face, 0, GL_RGB16F, 1, 1, 0, GL_RGB, GL_FLOAT, &bgcolor); 1.283 + } 1.284 + } 1.285 +} 1.286 + 1.287 +#define XFORM_LINE_WIDTH OBJ_LINE_WIDTH 1.288 +void GPUScene::create_xform_texture() 1.289 +{ 1.290 + int tex_xsz = XFORM_LINE_WIDTH; 1.291 + int tex_ysz = next_pow2((int)objects.size() + 1); // leave space for the descriptor 1.292 + 1.293 + glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]); 1.294 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0); 1.295 + 1.296 + update_xform_texture(); 1.297 +} 1.298 + 1.299 +void GPUScene::update_xform_texture() 1.300 +{ 1.301 + int tex_xsz = XFORM_LINE_WIDTH; 1.302 + int tex_ysz = next_pow2((int)objects.size() + 1); // leave space for the descriptor 1.303 + 1.304 + if(!xform_buf) { 1.305 + xform_buf = new Vector4[tex_xsz * tex_ysz]; 1.306 + xform_buf[0].x = tex_ysz; // descriptor 1.307 + } 1.308 + 1.309 + Vector4 *pixptr = xform_buf + tex_xsz; 1.310 + for(auto obj : objects) { 1.311 + for(int i=0; i<4; i++) { 1.312 + pixptr[i] = obj->xform.get_column_vector(i); 1.313 + pixptr[i + 4] = obj->inv_xform.get_column_vector(i); 1.314 + } 1.315 + pixptr += tex_xsz; 1.316 + } 1.317 + 1.318 + glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]); 1.319 + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_xsz, tex_ysz, GL_RGBA, GL_FLOAT, xform_buf); 1.320 +}