gpuray_glsl

annotate src/gpuscene.cc @ 4:2ed3da7dc0bc

broken
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 10 Nov 2014 01:26:00 +0200
parents f234630e38ff
children
rev   line source
nuclear@0 1 #include <algorithm>
nuclear@0 2 #include <assert.h>
nuclear@0 3 #include "gpuscene.h"
nuclear@0 4 #include "sphere.h"
nuclear@0 5 #include "plane.h"
nuclear@0 6 #include "box.h"
nuclear@0 7 #include "opengl.h"
nuclear@0 8
nuclear@0 9 GPUScene::GPUScene()
nuclear@0 10 {
nuclear@0 11 glGenTextures(NUM_TEXTURES, textures);
nuclear@0 12
nuclear@0 13 for(int i=0; i<NUM_TEXTURES; i++) {
nuclear@0 14 glBindTexture(GL_TEXTURE_2D, textures[i]);
nuclear@0 15 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
nuclear@0 16 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
nuclear@0 17 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
nuclear@0 18 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
nuclear@0 19 }
nuclear@0 20
nuclear@0 21 xform_buf = 0;
nuclear@0 22 }
nuclear@0 23
nuclear@0 24 GPUScene::~GPUScene()
nuclear@0 25 {
nuclear@0 26 glDeleteTextures(NUM_TEXTURES, textures);
nuclear@0 27 delete [] xform_buf;
nuclear@0 28 }
nuclear@0 29
nuclear@0 30 bool GPUScene::create_textures()
nuclear@0 31 {
nuclear@0 32 // must be first to generate the megatecture rectangles
nuclear@0 33 create_megatexture();
nuclear@0 34
nuclear@0 35 Sphere *sph;
nuclear@0 36 Plane *plane;
nuclear@0 37 Box *box;
nuclear@4 38 Cone *cone;
nuclear@0 39
nuclear@0 40 std::vector<Sphere*> spheres;
nuclear@0 41 std::vector<Plane*> planes;
nuclear@0 42 std::vector<Box*> boxes;
nuclear@4 43 std::vector<Cone*> cones;
nuclear@0 44
nuclear@0 45 // collect all objects into the different type-specific arrays
nuclear@0 46 for(auto obj : objects) {
nuclear@0 47 if((sph = dynamic_cast<Sphere*>(obj))) {
nuclear@0 48 spheres.push_back(sph);
nuclear@0 49
nuclear@0 50 } else if((plane = dynamic_cast<Plane*>(obj))) {
nuclear@0 51 planes.push_back(plane);
nuclear@0 52
nuclear@0 53 } else if((box = dynamic_cast<Box*>(obj))) {
nuclear@0 54 boxes.push_back(box);
nuclear@0 55
nuclear@4 56 } else if((cone = dynamic_cast<Cone*>(obj))) {
nuclear@4 57 cones.push_back(cone);
nuclear@4 58
nuclear@0 59 } else {
nuclear@0 60 fprintf(stderr, "skipping object of unknown type: %s\n", obj->get_name());
nuclear@0 61 }
nuclear@0 62 }
nuclear@0 63
nuclear@0 64 create_sphere_texture(spheres);
nuclear@0 65 create_plane_texture(planes);
nuclear@0 66 create_box_texture(boxes);
nuclear@4 67 create_cone_texture(cones);
nuclear@0 68
nuclear@0 69 create_env_texture();
nuclear@0 70 create_xform_texture();
nuclear@0 71
nuclear@0 72 return true;
nuclear@0 73 }
nuclear@0 74
nuclear@0 75 unsigned int GPUScene::get_texture(int which) const
nuclear@0 76 {
nuclear@0 77 return textures[which];
nuclear@0 78 }
nuclear@0 79
nuclear@0 80 #define MAT_START 4
nuclear@0 81 static void copy_material(Vector4 *ptr, const Material *mtl)
nuclear@0 82 {
nuclear@0 83 ptr[MAT_START].x = mtl->diffuse.x;
nuclear@0 84 ptr[MAT_START].y = mtl->diffuse.y;
nuclear@0 85 ptr[MAT_START].z = mtl->diffuse.z;
nuclear@0 86 ptr[MAT_START].w = mtl->transparency;
nuclear@0 87
nuclear@0 88 ptr[MAT_START + 1].x = mtl->specular.x;
nuclear@0 89 ptr[MAT_START + 1].y = mtl->specular.y;
nuclear@0 90 ptr[MAT_START + 1].z = mtl->specular.z;
nuclear@0 91 ptr[MAT_START + 1].w = mtl->shininess;
nuclear@0 92
nuclear@0 93 ptr[MAT_START + 2].x = mtl->reflectivity;
nuclear@0 94 ptr[MAT_START + 2].y = mtl->ior;
nuclear@0 95
nuclear@0 96 ptr[MAT_START + 3] = mtl->mega_rect;
nuclear@0 97 }
nuclear@0 98
nuclear@0 99 int GPUScene::object_index(const Object *obj) const
nuclear@0 100 {
nuclear@0 101 for(int i=0; i<(int)objects.size(); i++) {
nuclear@0 102 if(objects[i] == obj) {
nuclear@0 103 return i;
nuclear@0 104 }
nuclear@0 105 }
nuclear@0 106 abort(); // can't happen
nuclear@0 107 return -1;
nuclear@0 108 }
nuclear@0 109
nuclear@0 110 #define OBJ_LINE_WIDTH 16
nuclear@0 111 void GPUScene::create_sphere_texture(const std::vector<Sphere*> &spheres)
nuclear@0 112 {
nuclear@0 113 int xsz = OBJ_LINE_WIDTH;
nuclear@0 114 int ysz = (int)spheres.size() + 1;
nuclear@0 115 int tex_ysz = next_pow2(ysz);
nuclear@0 116
nuclear@0 117 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@0 118
nuclear@0 119 pixels[0].x = (float)ysz;
nuclear@0 120 pixels[0].y = (float)tex_ysz;
nuclear@0 121 pixels[0].z = 0.5;
nuclear@0 122 pixels[0].w = 1.0;
nuclear@0 123
nuclear@0 124 Vector4 *pixptr = pixels + xsz;
nuclear@0 125
nuclear@0 126 for(size_t i=0; i<spheres.size(); i++) {
nuclear@0 127 pixptr[0].x = object_index(spheres[i]);
nuclear@0 128
nuclear@0 129 pixptr[1].x = spheres[i]->pos.x;
nuclear@0 130 pixptr[1].y = spheres[i]->pos.y;
nuclear@0 131 pixptr[1].z = spheres[i]->pos.z;
nuclear@0 132 pixptr[1].w = spheres[i]->radius;
nuclear@0 133
nuclear@0 134 copy_material(pixptr, &spheres[i]->material);
nuclear@0 135 pixptr += OBJ_LINE_WIDTH;
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 glBindTexture(GL_TEXTURE_2D, textures[TEX_SPHERE]);
nuclear@0 139 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@0 140
nuclear@0 141 delete [] pixels;
nuclear@0 142 }
nuclear@0 143
nuclear@0 144 void GPUScene::create_plane_texture(const std::vector<Plane*> &planes)
nuclear@0 145 {
nuclear@0 146 int xsz = OBJ_LINE_WIDTH;
nuclear@0 147 int ysz = (int)planes.size() + 1;
nuclear@0 148 int tex_ysz = next_pow2(ysz);
nuclear@0 149
nuclear@0 150 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@0 151
nuclear@0 152 pixels[0].x = (float)ysz;
nuclear@0 153 pixels[0].y = (float)tex_ysz;
nuclear@0 154
nuclear@0 155 Vector4 *pixptr = pixels + xsz;
nuclear@0 156
nuclear@0 157 for(size_t i=0; i<planes.size(); i++) {
nuclear@0 158 pixptr[0].x = object_index(planes[i]);
nuclear@0 159
nuclear@0 160 pixptr[1].x = planes[i]->normal.x;
nuclear@0 161 pixptr[1].y = planes[i]->normal.y;
nuclear@0 162 pixptr[1].z = planes[i]->normal.z;
nuclear@0 163 pixptr[1].w = planes[i]->dist;
nuclear@0 164
nuclear@0 165 copy_material(pixptr, &planes[i]->material);
nuclear@0 166 pixptr += OBJ_LINE_WIDTH;
nuclear@0 167 }
nuclear@0 168
nuclear@0 169 glBindTexture(GL_TEXTURE_2D, textures[TEX_PLANE]);
nuclear@0 170 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@0 171
nuclear@0 172 delete [] pixels;
nuclear@0 173 }
nuclear@0 174
nuclear@0 175 void GPUScene::create_box_texture(const std::vector<Box*> &boxes)
nuclear@0 176 {
nuclear@0 177 int xsz = OBJ_LINE_WIDTH;
nuclear@0 178 int ysz = (int)boxes.size() + 1;
nuclear@0 179 int tex_ysz = next_pow2(ysz);
nuclear@0 180
nuclear@0 181 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@0 182
nuclear@0 183 pixels[0].x = (float)ysz;
nuclear@0 184 pixels[0].y = (float)tex_ysz;
nuclear@0 185
nuclear@0 186 Vector4 *pixptr = pixels + xsz;
nuclear@0 187
nuclear@0 188 for(size_t i=0; i<boxes.size(); i++) {
nuclear@0 189 pixptr[0].x = object_index(boxes[i]);
nuclear@0 190 pixptr[1] = boxes[i]->min;
nuclear@0 191 pixptr[2] = boxes[i]->max;
nuclear@0 192
nuclear@0 193 copy_material(pixptr, &boxes[i]->material);
nuclear@0 194 pixptr += OBJ_LINE_WIDTH;
nuclear@0 195 }
nuclear@0 196
nuclear@0 197 glBindTexture(GL_TEXTURE_2D, textures[TEX_BOX]);
nuclear@0 198 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@0 199
nuclear@0 200 delete [] pixels;
nuclear@0 201 }
nuclear@0 202
nuclear@4 203 void GPUScene::create_cone_texture(const std::vector<Cone*> &cones)
nuclear@4 204 {
nuclear@4 205 int xsz = OBJ_LINE_WIDTH;
nuclear@4 206 int ysz = (int)cones.size() + 1;
nuclear@4 207 int tex_ysz = next_pow2(ysz);
nuclear@4 208
nuclear@4 209 Vector4 *pixels = new Vector4[xsz * tex_ysz];
nuclear@4 210
nuclear@4 211 pixels[0].x = (float)ysz;
nuclear@4 212 pixels[0].y = (float)tex_ysz;
nuclear@4 213
nuclear@4 214 Vector4 *pixptr = pixels + xsz;
nuclear@4 215
nuclear@4 216 for(size_t i=0; i<cones.size(); i++) {
nuclear@4 217 pixptr[0].x = object_index(cones[i]);
nuclear@4 218
nuclear@4 219 pixptr[1].x = cones[i]->angle;
nuclear@4 220 pixptr[1].y = cones[i]->ymin;
nuclear@4 221 pixptr[1].z = cones[i]->ymax;
nuclear@4 222 pixptr[1].w = 0.0;
nuclear@4 223
nuclear@4 224 copy_material(pixptr, &cones[i]->material);
nuclear@4 225 pixptr += OBJ_LINE_WIDTH;
nuclear@4 226 }
nuclear@4 227
nuclear@4 228 glBindTexture(GL_TEXTURE_2D, textures[TEX_SPHERE]);
nuclear@4 229 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, pixels);
nuclear@4 230
nuclear@4 231 delete [] pixels;
nuclear@4 232 }
nuclear@4 233
nuclear@4 234
nuclear@0 235 void GPUScene::create_megatexture()
nuclear@0 236 {
nuclear@0 237 // at least a 1x1 dummy white texture
nuclear@0 238 int xsz = 1;
nuclear@0 239 int ysz = 1;
nuclear@0 240 int num_textures = 0;
nuclear@0 241
nuclear@0 242 for(auto obj : objects) {
nuclear@0 243 // only need 2D textures at this point
nuclear@0 244 Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
nuclear@0 245 if(tex) {
nuclear@0 246 const Image *img = tex->get_image();
nuclear@0 247
nuclear@0 248 xsz = std::max(xsz, img->xsz);
nuclear@0 249 ysz += img->ysz;
nuclear@0 250 num_textures++;
nuclear@0 251 }
nuclear@0 252 }
nuclear@0 253
nuclear@0 254 int tex_xsz = next_pow2(xsz);
nuclear@0 255 int tex_ysz = next_pow2(ysz);
nuclear@0 256
nuclear@0 257 Color *pixels = new Color[tex_xsz * tex_ysz];
nuclear@0 258
nuclear@0 259 // null texture
nuclear@0 260 pixels[0] = Color(1, 1, 1);
nuclear@0 261
nuclear@0 262 Color *pixptr = pixels + tex_xsz;
nuclear@0 263
nuclear@0 264 float offs_y = 0.0;
nuclear@0 265 for(auto obj : objects) {
nuclear@0 266 Texture *tex = dynamic_cast<Texture2D*>(obj->material.tex);
nuclear@0 267 if(tex) {
nuclear@0 268 const Image *img = tex->get_image();
nuclear@0 269
nuclear@0 270 Vector4 rect{0.0, offs_y, (float)img->xsz / (float)tex_xsz,
nuclear@0 271 (float)img->ysz / (float)tex_ysz};
nuclear@0 272
nuclear@0 273 offs_y += rect.w;
nuclear@0 274
nuclear@0 275 obj->material.mega_rect = rect;
nuclear@0 276
nuclear@0 277 for(int i=0; i<img->ysz; i++) {
nuclear@0 278 memcpy(pixptr, img->pixels + i * img->xsz, img->xsz * sizeof *pixels);
nuclear@0 279 pixptr += tex_xsz;
nuclear@0 280 }
nuclear@0 281 } else {
nuclear@0 282 obj->material.mega_rect = Vector4(0, 0, 0, 0);
nuclear@0 283 }
nuclear@0 284 }
nuclear@0 285
nuclear@0 286 glBindTexture(GL_TEXTURE_2D, textures[TEX_TEXTURE]);
nuclear@0 287 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, tex_xsz, tex_ysz, 0, GL_RGB, GL_FLOAT, pixels);
nuclear@0 288
nuclear@0 289 delete [] pixels;
nuclear@0 290 }
nuclear@0 291
nuclear@0 292 void GPUScene::create_env_texture()
nuclear@0 293 {
nuclear@0 294 // create the scene cubemap, or a null cubemap if we don't have one
nuclear@0 295 glDeleteTextures(1, textures + TEX_ENV); // cause it's not a 2D texture :)
nuclear@0 296
nuclear@0 297 glGenTextures(1, textures + TEX_ENV);
nuclear@0 298 glBindTexture(GL_TEXTURE_CUBE_MAP, textures[TEX_ENV]);
nuclear@0 299 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 300 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 301 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
nuclear@0 302 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
nuclear@0 303 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
nuclear@0 304
nuclear@0 305 if(envmap) {
nuclear@0 306 // we have an environment cubemap, just pass the data to OpenGL
nuclear@0 307 for(int i=0; i<6; i++) {
nuclear@0 308 const Image *img = envmap->get_image(i);
nuclear@0 309
nuclear@0 310 int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
nuclear@0 311 glTexImage2D(face, 0, GL_RGB16F, img->xsz, img->ysz, 0, GL_RGB, GL_FLOAT, img->pixels);
nuclear@0 312 }
nuclear@0 313 } else {
nuclear@0 314 // we don't have an env cubemap, make a dummy 1x1 cubemap with the background color
nuclear@0 315 for(int i=0; i<6; i++) {
nuclear@0 316 int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
nuclear@0 317 glTexImage2D(face, 0, GL_RGB16F, 1, 1, 0, GL_RGB, GL_FLOAT, &bgcolor);
nuclear@0 318 }
nuclear@0 319 }
nuclear@0 320 }
nuclear@0 321
nuclear@0 322 #define XFORM_LINE_WIDTH OBJ_LINE_WIDTH
nuclear@0 323 void GPUScene::create_xform_texture()
nuclear@0 324 {
nuclear@0 325 int tex_xsz = XFORM_LINE_WIDTH;
nuclear@0 326 int tex_ysz = next_pow2((int)objects.size() + 1); // leave space for the descriptor
nuclear@0 327
nuclear@0 328 glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
nuclear@0 329 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, tex_xsz, tex_ysz, 0, GL_RGBA, GL_FLOAT, 0);
nuclear@0 330
nuclear@0 331 update_xform_texture();
nuclear@0 332 }
nuclear@0 333
nuclear@0 334 void GPUScene::update_xform_texture()
nuclear@0 335 {
nuclear@0 336 int tex_xsz = XFORM_LINE_WIDTH;
nuclear@0 337 int tex_ysz = next_pow2((int)objects.size() + 1); // leave space for the descriptor
nuclear@0 338
nuclear@0 339 if(!xform_buf) {
nuclear@0 340 xform_buf = new Vector4[tex_xsz * tex_ysz];
nuclear@0 341 xform_buf[0].x = tex_ysz; // descriptor
nuclear@0 342 }
nuclear@0 343
nuclear@0 344 Vector4 *pixptr = xform_buf + tex_xsz;
nuclear@0 345 for(auto obj : objects) {
nuclear@0 346 for(int i=0; i<4; i++) {
nuclear@0 347 pixptr[i] = obj->xform.get_column_vector(i);
nuclear@0 348 pixptr[i + 4] = obj->inv_xform.get_column_vector(i);
nuclear@0 349 }
nuclear@0 350 pixptr += tex_xsz;
nuclear@0 351 }
nuclear@0 352
nuclear@0 353 glBindTexture(GL_TEXTURE_2D, textures[TEX_XFORM]);
nuclear@0 354 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, tex_xsz, tex_ysz, GL_RGBA, GL_FLOAT, xform_buf);
nuclear@0 355 }