RGBAPixel GeometricObject::rayTrace(PointLight& lightSrc, Point3D& pt, Ray& viewRay, vector<GeometricObject*>& shapes){ RGBAPixel color = material.color; if(texture != NULL) color = *mapToTexture(pt); Vector3D dir(lightSrc.o,pt); dir.normalize(); Point3D tempPt(pt+dir.reflect()*0.01); Ray backtraceRay(tempPt,dir.reflect(), "shadow"); //from hit point on shape to light source double tHitLight = lightSrc.o.distance(pt); bool shadow = false; Point3D trash(0,0,0); for(int i = 0; i < shapes.size(); i++){ if(shapes[i]->isLightSrc) continue; double tHitAnotherShape = shapes[i]->hit(backtraceRay,trash); if(tHitAnotherShape < tHitLight && tHitAnotherShape > 0){ shadow = true; break; } } //pt's intersection with viewRay and geometry Vector3D n(this->getNormal(pt)); n.normalize(); double r = 0.0; double g = 0.0; double b = 0.0; //Ambient Lighting r += 0.04 * 30; g += 0.04 * 30; b += 0.04 * 30; RGBAPixel temp(r*color.red, g*color.green ,b*color.blue); if(shadow){ return temp; } //Diffuse Lighting Vector3D reflectRay = (dir.reflect()).hat(); double product = reflectRay.dot(n); if (product > 0){ r += color.red*product * material.kd; g += color.green*product * material.kd; b += color.blue*product * material.kd; } //Specular Lighting double epsilon = 10.0; Vector3D rVec(dir - (n*dir.dot(n)*2.0)); double spec = rVec.dot(viewRay.d.reflect()); double rw0e; if(spec > 0) rw0e = pow(spec,epsilon); else rw0e = 0; if(product > 0){ r += color.red*rw0e * material.ks * 0.5; g += color.green*rw0e * material.ks * 0.5; b += color.blue*rw0e * material.ks * 0.5; } r = r*material.directScale; g = g*material.directScale; b = b*material.directScale; //Reflections double minTime = 100000.0; double tHitAnotherShape = 0.0; Vector3D recViewDir(viewRay.d - (2*viewRay.d*n)*n); //direction of mirror reflection recViewDir.normalize(); Ray recViewRay(pt,recViewDir, "view"); recViewRay.recurseLevel = viewRay.recurseLevel+1; Point3D recPt; RGBAPixel recColor; //Mirror Reflection if(material.reflectProperty == "mirror" && viewRay.recurseLevel < 3){ GeometricObject* nextShape = NULL; for(int k = 0; k < shapes.size(); k++){ if(shapes[k] == this) continue; tHitAnotherShape = shapes[k]->hit(recViewRay,recPt); if(tHitAnotherShape > 0.0 && tHitAnotherShape < minTime){ nextShape = shapes[k]; minTime = tHitAnotherShape; } } if(nextShape != NULL){ recColor = nextShape->rayTrace(lightSrc, recPt, recViewRay, shapes); r += (recColor.red); //* (1-material.directScale); g += (recColor.green);// * (1-material.directScale); b += (recColor.blue);// * (1-material.directScale); } } if(material.reflectProperty == "glossy" && viewRay.recurseLevel < 3){ double tempR = 0.0; double tempG = 0.0; double tempB = 0.0; Vector3D axisA = Vector3D(1,0,0).cross(recViewDir).hat() * 1; Vector3D axisB = axisA.cross(recViewDir).hat() * 1; Point3D tempPt = pt + recViewDir - 0.5*axisA - 0.5*axisB; Rectangle rect(tempPt, axisA, axisB); vector<Point3D> samplepts = rect.generatePoints(100); for(int i = 0; i < samplepts.size(); i++){ Vector3D indirectDir(pt,samplepts[i]); Ray indirectRay(pt,indirectDir); indirectRay.recurseLevel = viewRay.recurseLevel + 1; GeometricObject* nextShape = NULL; double minTime = 100000.0; double tHitAnotherShape = 0.0; for(int k = 0; k < shapes.size(); k++){ if(shapes[k] == this) continue; tHitAnotherShape = shapes[k]->hit(indirectRay,recPt); if(tHitAnotherShape > 0.0 && tHitAnotherShape < minTime){ nextShape = shapes[k]; minTime = tHitAnotherShape; } if(nextShape != NULL && nextShape->material.transparency == 0){ recColor = nextShape->rayTrace(lightSrc, recPt, recViewRay, shapes); tempR += (recColor.red); tempG += (recColor.green); tempB += (recColor.blue); } } } r += tempR / samplepts.size(); g += tempG / samplepts.size(); b += tempB / samplepts.size(); } if(material.transparency > 0 && viewRay.recurseLevel == 0){ double tempR = 255; double tempG = 255; double tempB = 255; Vector3D invNormal = n.reflect(); Ray inverseRay(pt,invNormal); inverseRay.recurseLevel = viewRay.recurseLevel + 1; GeometricObject* nextShape = NULL; double minTime = 100000.0; double tHitAnotherShape = 0.0; for(int k = 0; k < shapes.size(); k++){ if(shapes[k] == this) continue; tHitAnotherShape = shapes[k]->hit(inverseRay,recPt); if(tHitAnotherShape > 0.0 && tHitAnotherShape < minTime){ nextShape = shapes[k]; minTime = tHitAnotherShape; } if(nextShape != NULL && nextShape != this){ recColor = nextShape->rayTrace(lightSrc, recPt, inverseRay, shapes); tempR = (recColor.red); tempG = (recColor.green); tempB = (recColor.blue); } } r = tempR * material.transparency + (r*(1-material.transparency)); g = tempG * material.transparency + (g*(1-material.transparency)); b = tempB * material.transparency + (b*(1-material.transparency)); } //cap off maximum color values r =std::min((int)r,255); g =std::min((int)g,255); b =std::min((int)b,255); temp(r,g,b); return temp; }
NoDice::Font:: Font(const std::string& fontname, unsigned int pointsize) : m_name(fontname) , m_height(pointsize) , m_glyph(s_max_char) { // Calculate the maximum extent of textures supported by OpenGL. GLint max_tex_width; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_width); FT_Library ftLib; FT_Error ftStatus = FT_Init_FreeType(&ftLib); if (ftStatus != 0) { throw std::runtime_error("error in FT_Init_Freetype"); } FT_Face ftFace; ftStatus = FT_New_Face(ftLib, m_name.c_str(), 0, &ftFace); if (ftStatus != 0) { throw std::runtime_error("error in FT_New_Face"); } // munge character size. Freetype uses 1/64th of a point (1/4608 of an inch) // as its base unit, but the pointsize parameter of this function is in // points. Conversion requires multiplying by 64, which is what the // shift-by-size operation does. // // I'm also assuming a screen pitch of 100 dots-per-inch. This needs to be // adjusted to use autodetected or configurable values if possible. // @todo fix assumptions about screen dot pitch // int dpi = 100; ftStatus = FT_Set_Char_Size(ftFace, pointsize<<6, pointsize<<6, dpi, dpi); // Import the bitmap for each character in the font. This go-round, we're // only supportin 7-bit ASCII. // @todo fix assumptions about character sets GLsizei curTexWidth = 0; GLsizei maxTexWidth = 0; GLsizei curTexHeight = 0; GLsizei maxTexHeight = 0; int glyphCount = 0; for (unsigned char c = 0; c < s_max_char; ++c) { ftStatus = FT_Load_Char(ftFace, c, FT_LOAD_RENDER); if (ftStatus != 0) { throw std::runtime_error("error in FT_Load_Glyph"); } m_glyph[c].left = ftFace->glyph->bitmap_left; m_glyph[c].top = ftFace->glyph->bitmap_top; m_glyph[c].width = ftFace->glyph->bitmap.width; m_glyph[c].height = ftFace->glyph->bitmap.rows; m_glyph[c].advance = ftFace->glyph->advance.x >> 6; // If this glyph fits in current line, add to totals otherwise start a new // line. if (curTexWidth + m_glyph[c].width < max_tex_width) { curTexWidth += m_glyph[c].width; curTexHeight = std::max(curTexHeight, m_glyph[c].height); ++glyphCount; } else { maxTexWidth = std::max(maxTexWidth, curTexWidth); curTexWidth = m_glyph[c].width; maxTexHeight += std::max(curTexHeight, m_glyph[c].height); curTexHeight = 0; glyphCount = 0; } // Allocate the required memory for this glyph's bitmap. // // The bitmap needs width*height bytes for the luminance component // and the same again for the glyph's alpha component. m_glyph[c].bitmap = Glyph::Bitmap(m_glyph[c].width * m_glyph[c].height * 2*sizeof(GLubyte)); // Convert the freefont bitmap into an opengl GL_LUMINANCE_ALPHA bitmap by // setting the alpha to 255 (0xff) wherever the luminance is greater than // zero. See, a lot of truetype fonts have built-in antialiasing. This // mechanism trats a zero luminance as a transparent background. int i = 0; for (int y = 0; y < m_glyph[c].height; ++y) { for (int x = 0; x < m_glyph[c].width; ++x) { int index = x + m_glyph[c].width*y; m_glyph[c].bitmap[i++] = ftFace->glyph->bitmap.buffer[index]; m_glyph[c].bitmap[i++] = (ftFace->glyph->bitmap.buffer[index] > 0 ? 0xff : 0); } } } FT_Done_Face(ftFace); FT_Done_FreeType(ftLib); maxTexWidth = std::max(maxTexWidth, curTexWidth); maxTexHeight += curTexHeight; m_textureWidth = nextPowerOfTwo(maxTexWidth); m_textureHeight = nextPowerOfTwo(maxTexHeight); mapToTexture(); }