void nglInterpolateVertexZ(const VERTEX *from, const VERTEX *to, VERTEX *res) { GLFix diff = to->z - from->z; if(diff < GLFix(1) && diff > GLFix(-1)) diff = 1; GLFix t = (GLFix(CLIP_PLANE) - from->z) / diff; res->x = from->x + (to->x - from->x) * t; res->y = from->y + (to->y - from->y) * t; res->z = CLIP_PLANE; #ifdef TEXTURE_SUPPORT res->u = from->u + (to->u - from->u) * t; res->u = res->u.wholes(); res->v = from->v + (to->v - from->v) * t; res->v = res->v.wholes(); #endif #ifdef INTERPOLATE_COLORS RGB c_from = rgbColor(from->c); RGB c_to = rgbColor(to->c); res->c = colorRGB(c_from.r + (c_to.r - c_from.r) * t, c_from.r + (c_to.r - c_from.r) * t, c_from.r + (c_to.r - c_from.r) * t); #else res->c = from->c; #endif }
static void interpolateVertexXRight(const VERTEX *from, const VERTEX *to, VERTEX *res) { GLFix diff = to->x - from->x; if(diff < GLFix(1) && diff > GLFix(-1)) diff = 1; GLFix end = (SCREEN_WIDTH - 1); GLFix t = (end - from->x) / diff; res->x = end; res->y = from->y + (to->y - from->y) * t; res->z = from->z + (to->z - from->z) * t; #ifdef TEXTURE_SUPPORT res->u = from->u + (to->u - from->u) * t; res->u = res->u.wholes(); res->v = from->v + (to->v - from->v) * t; res->v = res->v.wholes(); #endif #ifdef INTERPOLATE_COLORS RGB c_from = rgbColor(from->c); RGB c_to = rgbColor(to->c); res->c = colorRGB(c_from.r + (c_to.r - c_from.r) * t, c_from.r + (c_to.r - c_from.r) * t, c_from.r + (c_to.r - c_from.r) * t); #else res->c = from->c; #endif }
/**************************************************************************** REMARKS: Draw the background image for the centering and refresh display ****************************************************************************/ static void drawBackground(void) { char buf[80]; int i,x,y,min,max; long range; GA_palette pal[256],*p; min = 32; max = 253; range = max - min; for (i = 0; i < 254; i++) { pal[i].Red = 0; pal[i].Blue = (((i*range)/254)+min); pal[i].Green = 0; } pal[254].Red = pal[254].Green = pal[254].Blue = 128; pal[255].Red = pal[255].Green = pal[255].Blue = 255; if (modeInfo.BitsPerPixel > 8) { for (i = 0; i < maxY; i++) { p = &pal[(i * 254L) / maxY]; SetForeColor(rgbColor(p->Red,p->Green,p->Blue)); draw2d.DrawLineInt(0,i,maxX,i,true); } } else { driver.SetPaletteData(pal,256,0,false); for (i = 0; i < maxY; i++) { SetForeColor((i * 254L) / maxY); draw2d.DrawLineInt(0,i,maxX,i,true); } defcolor = 255; } SetForeColor(defcolor); draw2d.DrawLineInt(0,0,maxX,0,true); draw2d.DrawLineInt(0,0,0,maxY,true); draw2d.DrawLineInt(maxX,0,maxX,maxY,true); draw2d.DrawLineInt(0,maxY,maxX,maxY,true); draw2d.DrawLineInt(maxX/2,0,maxX/2,maxY,true); draw2d.DrawLineInt(0,maxY/2,maxX,maxY/2,true); x = maxX/2 - 240; y = maxY/2 - 146; sprintf(buf,"Video mode: %d x %d %d bits per pixel",maxX+1,maxY+1,modeInfo.BitsPerPixel); WriteText(x,y,buf,defcolor); y += 32; WriteText(x,y,"Adjust mode parameters with the following keys:",defcolor); y += 32; WriteText(x,y," \x1B Move image left",defcolor); y += 16; WriteText(x,y," \x1A Move image right",defcolor); y += 16; WriteText(x,y," \x18 Move image up",defcolor); y += 16; WriteText(x,y," \x19 Move image down",defcolor); y += 16; WriteText(x,y," + Increase brightness",defcolor); y += 16; WriteText(x,y," - Decrease brightness",defcolor); y += 16; WriteText(x,y," r Restore original values",defcolor); y += 16; y += 16; WriteText(x,y,"Press <Enter> to accept changes, ESC to quit without saving",defcolor); }
//Some textures have a different color in different biomes. We have to make them green. Grey grass just looks so unhealty static void makeColor(const RGB &color, TEXTURE &texture, const int x, const int y, const int w, const int h) { for(int x1 = x; x1 < w + x; x1++) for(int y1 = y; y1 < h + y; y1++) { RGB grey = rgbColor(texture.bitmap[x1 + y1*texture.width]); grey.r *= color.r; grey.g *= color.g; grey.b *= color.b; texture.bitmap[x1 + y1*texture.width] = colorRGB(grey); } }
rgbColor newWard::f(const vec3& wo, const vec3& wi) const{ if(wo.y*wi.y < 0.f){ return rgbColor(0.f); } const vec3 wh = halfVector(wo, wi); const float meanX = wh.x / alpha; const float meanZ = wh.z / beta; return Rs * exp( -(meanX*meanX + meanZ*meanZ) / (wh.y*wh.y)) / (4.f * PI * alpha * beta * sqrt(wo.y*wi.y)); }
rgbColor newWard::sampleF(const float& u0, const float& u1, const vec3& wo, vec3& wi, float& pd) const{ if(wo.y < 0.f) { pd = 0.f; return rgbColor(0.f); } const float phi = isIsotropic ? TWOPI * u0 : atan2(beta * sin(TWOPI * u0), alpha * cos(TWOPI * u0)); const float cosPhi = cos(phi); const float sinPhi = sin(phi); const float theta = isIsotropic ? atan(alpha * sqrt(-logf(u1))) : atan( sqrt(-logf(u1) / ((cosPhi*cosPhi)/(alpha*alpha) + (sinPhi*sinPhi)/(beta*beta))) ); vec3 wh; sphericalToDirection(wh, sin(theta), cos(theta), phi); wh = normalize(wh); // Find the incident direction that corresponds to this half vector and the // reflected direction. wi = 2.f * dot(wo, wh) * wh - wo; if(wi.y < 0.f){ pd = 0.f; return rgbColor(0.f); } // For the derivation of this PDF and the fact that it isn't the one // computed below, see Bruce Walter's TR from Cornell: PCG-05-06). // // Lots of cancellation between BRDF and PDF -> simpler calculations. pd = sqrt(wi.y*wo.y) / (abs(dot(wh, wo)) * pow(wh.y, 3)); return Rs; }
rgbColor substrate::sampleF(const float& u0, const float& u1, const vec3& wo, vec3& wi, float& pd) const{ if(u0 < 0.5f){ const float u = 2.f * u0; cosineSampleHemisphere(wi, u, u1); }else{ const float u = 2.f * (u0 - 0.5f); distrib->sampleF(u, u1, wo, wi, pd); if(wo.y * wi.y < 0){ return rgbColor(0.f); } } pd = pdf(wo, wi); return f(wo, wi); }
/**************************************************************************** REMARKS: Draw a simple moire pattern of lines on the display ****************************************************************************/ void DrawMoire(void) { int i,value; if (maxcolor >= 0x7FFFL) { for (i = 0; i < maxX; i++) { SetForeColor(rgbColor((uchar)((i*255L)/maxX),0,0)); draw2d.DrawLineInt(maxX/2,maxY/2,i,0,rgbColor((uchar)((i*255L)/maxX),0,0)); SetForeColor(rgbColor(0,(uchar)((i*255L)/maxX),0)); draw2d.DrawLineInt(maxX/2,maxY/2,i,maxY,rgbColor(0,(uchar)((i*255L)/maxX),0)); } for (i = 0; i < maxY; i++) { value = (int)((i*255L)/maxY); SetForeColor(rgbColor((uchar)value,0,(uchar)(255 - value))); draw2d.DrawLineInt(maxX/2,maxY/2,0,i,rgbColor((uchar)value,0,(uchar)(255 - value))); SetForeColor(rgbColor(0,(uchar)(255 - value),(uchar)value)); draw2d.DrawLineInt(maxX/2,maxY/2,maxX,i,rgbColor(0,(uchar)(255 - value),(uchar)value)); } } else { for (i = 0; i < maxX; i += 5) { SetForeColor(i % maxcolor); draw2d.DrawLineInt(maxX/2,maxY/2,i,0,true); SetForeColor((i+1) % maxcolor); draw2d.DrawLineInt(maxX/2,maxY/2,i,maxY,true); } for (i = 0; i < maxY; i += 5) { SetForeColor((i+2) % maxcolor); draw2d.DrawLineInt(maxX/2,maxY/2,0,i,true); SetForeColor((i+3) % maxcolor); draw2d.DrawLineInt(maxX/2,maxY/2,maxX,i,true); } } SetForeColor(defcolor); draw2d.DrawLineInt(0,0,maxX,0,true); draw2d.DrawLineInt(0,0,0,maxY,true); draw2d.DrawLineInt(maxX,0,maxX,maxY,true); draw2d.DrawLineInt(0,maxY,maxX,maxY,true); }
void Screen::savePng(char * outputFilename) const { clock_t startTimer, endTimer; printf("Saving file to \"%s\"...", outputFilename); fflush(stdout); startTimer = clock(); int pixelCount = height * width; std::vector<unsigned char> png; for (int i = pixelCount - 1; i >=0; i--) { RGBColor rgbColor(pixels[i]); png.push_back(rgbColor.r); png.push_back(rgbColor.g); png.push_back(rgbColor.b); png.push_back(255); } lodepng::encode(outputFilename, png, width, height); endTimer = clock(); printf("completed (%.3f seconds).\n", clockTime(startTimer, endTimer)); }
void AP_Win32Dialog_Background::runModal(XAP_Frame * pFrame) { UT_return_if_fail (pFrame); const gchar * pszC = getColor(); UT_RGBColor rgbColor(255,255,255); if(strcmp(pszC,"transparent") != 0) { UT_parseColor(pszC,rgbColor); } CHOOSECOLOR cc; // common dialog box structure static COLORREF acrCustClr[16]; // array of custom colors DWORD rgbCurrent; // initial color selection rgbCurrent = RGB( rgbColor.m_red, rgbColor.m_grn, rgbColor.m_blu ); // Initialize CHOOSECOLOR ZeroMemory(&cc, sizeof(CHOOSECOLOR)); cc.lStructSize = sizeof(CHOOSECOLOR); cc.hwndOwner = static_cast<XAP_Win32FrameImpl*>(pFrame->getFrameImpl())->getTopLevelWindow(); cc.lpCustColors = (LPDWORD) acrCustClr; cc.rgbResult = rgbCurrent; cc.Flags = CC_RGBINIT |CC_ENABLEHOOK; cc.lpfnHook = &AP_Win32Dialog_Background::s_hookProc; cc.lCustData = (LPARAM)this; if( ChooseColor(&cc) ) { rgbCurrent = cc.rgbResult; UT_setColor( rgbColor, GetRValue(rgbCurrent), GetGValue(rgbCurrent), GetBValue(rgbCurrent) ); setColor( rgbColor ); setAnswer( a_OK ); } else setAnswer( a_CANCEL ); }
RgbwColor::RgbwColor(const HsbColor& color) { RgbColor rgbColor(color); *this = rgbColor; }
// Function allocates and init a Game static game_p gameNew(engine_p engine, board_p board) { game_p game = NULL; context_p screen = NULL; int hd = 0; ASSERT(NULL != board, "gameNew"); game = (game_p)objectCreate( sizeof(game_t), (destructor_f)gameDestroy); game->board = boardRetain(board); screen = engineScreen(engine); game->width = contextWidth(screen); game->height = contextHeight(screen); game->padding = (game->width < game->height ? game->width : game->height) / 64; hd = engineHDSupported(engine); game->regular = fontRetain( fontLoad(hd ? fontNameRegularHD : fontNameRegularSD)); game->bold = fontRetain(fontLoad( hd ? fontNameBoldHD : fontNameBoldSD)); game->status_line = MAX(fontLine(game->regular), fontLine(game->bold)); game->images[0] = imageRetain( imageLoad(hd ? imageNameEmptyHD : imageNameEmptySD)); game->images[1] = imageRetain(imageLoad( hd ? imageName2HD : imageName2SD)); game->images[2] = imageRetain(imageLoad( hd ? imageName4HD : imageName4SD)); game->images[3] = imageRetain(imageLoad( hd ? imageName8HD : imageName8SD)); game->images[4] = imageRetain(imageLoad( hd ? imageName16HD : imageName16SD)); game->images[5] = imageRetain(imageLoad( hd ? imageName32HD : imageName32SD)); game->images[6] = imageRetain(imageLoad( hd ? imageName64HD : imageName64SD)); game->images[7] = imageRetain(imageLoad( hd ? imageName128HD : imageName128SD)); game->images[8] = imageRetain(imageLoad( hd ? imageName256HD : imageName256SD)); game->images[9] = imageRetain(imageLoad( hd ? imageName512HD : imageName512SD)); game->images[10] = imageRetain(imageLoad( hd ? imageName1024HD : imageName1024SD)); game->images[11] = imageRetain(imageLoad( hd ? imageName2048HD : imageName2048SD)); game->images[12] = imageRetain(imageLoad( hd ? imageName4096HD : imageName4096SD)); game->images[13] = imageRetain(imageLoad( hd ? imageName8192HD : imageName8192SD)); game->images[14] = imageRetain( imageLoad(hd ? imageName16384HD : imageName16384SD)); game->images[15] = imageRetain( imageLoad(hd ? imageName32768HD : imageName32768SD)); game->images[16] = imageRetain( imageLoad(hd ? imageName65536HD : imageName65536SD)); game->images[17] = imageRetain( imageLoad(hd ? imageName131072HD : imageName131072SD)); game->cell = MIN(imageWidth(game->images[0]), imageHeight(game->images[0])); game->board_back = rgbColor(0xBB, 0xAD, 0xA0); return game; };
rgbColor whittedRayTracer::_L(ray& r, const int& depth) const{ if(depth > MAX_DEPTH){ return rgbColor(0.f); } const intersection isect = parent.intersect(r); //return rgbColor(0, isect.debugInfo / 1e8, 0); if(!isect.hit){ return rgbColor(0.f); }else if(isect.li != NULL){ return isect.li->L(r); } material& mat = isect.li ? *isect.li->getMaterial().get() : *isect.s->getMaterial().get(); const vec3& normal = isect.shadingNormal; const bsdf& bsdf = mat.getBsdf(isect.uv); const vec3 wo = worldToBsdf(-r.direction, isect); bxdfType sampledType; rgbColor colorSum(0.f); if(isect.s->getMaterial()->isEmissive()){ return mat.Le(); } // Diffuse calculations. float lightPdf = 0.f; for(int i=0; i<parent.numLights(); ++i){ const light& li = parent.getLight(i); if(li.isPointSource()){ vec3 lightDir; const rgbColor Li = li.sampleL(r.origin, lightDir, sampleUniform(), sampleUniform(), lightPdf); const float lightDist = norm(lightDir); lightDir = normalize(lightDir); // Test for shadowing early. ray shadowRay(r.origin, lightDir); shadowRay.tMax = lightDist; if(!parent.intersectB(shadowRay)){ const vec3 wi = worldToBsdf(lightDir, isect); const rgbColor f = bsdf.f(wo, wi, bxdfType(DIFFUSE | GLOSSY | REFLECTION)) + mat.Le(); colorSum += f * dot(normal, lightDir) * (Li / lightPdf); } }else{ rgbColor areaContrib(0.f); for(int j=0; j<areaSamples; ++j){ vec3 lightDir; const rgbColor Li = li.sampleL(r.origin, lightDir, sampleUniform(), sampleUniform(), lightPdf); ray shadowRay(r.origin, normalize(lightDir)); shadowRay.tMax = norm(lightDir) + EPSILON; if(!parent.intersectB(shadowRay) && li.intersect(shadowRay).hit){ lightDir = normalize(lightDir); const vec3 wi = worldToBsdf(lightDir, isect); const rgbColor f = bsdf.f(wo, wi, bxdfType(DIFFUSE | GLOSSY | REFLECTION)) + mat.Le(); areaContrib += f * dot(normal, lightDir) * (Li / lightPdf); } } colorSum += areaContrib / (float)areaSamples; } } // Trace specular rays. vec3 specDir; float pdf; const rgbColor fr = bsdf.sampleF(sampleUniform(), sampleUniform(), sampleUniform(), wo, specDir, bxdfType(GLOSSY | SPECULAR | REFLECTION), sampledType, pdf); if(!fr.isBlack()){ specDir = bsdfToWorld(specDir, isect); ray r2(r.origin, specDir); colorSum += (fr / pdf) * _L(r2, depth+1) * abs(dot(specDir, normal)); } const rgbColor ft = bsdf.sampleF(sampleUniform(), sampleUniform(), sampleUniform(), wo, specDir, bxdfType(GLOSSY | SPECULAR | TRANSMISSION), sampledType, pdf); if(!ft.isBlack()){ specDir = bsdfToWorld(specDir, isect); ray r2(r.origin, specDir); colorSum += (ft / pdf) * _L(r2, depth+1) * abs(dot(specDir, normal)); } if(!isFinite(colorSum.avg())) { return ERROR_COLOR; } else { return colorSum; } }
void terrainInit(const char *texture_path) { terrain_current = loadTextureFromFile(texture_path); if(!terrain_current) terrain_current = &terrain; //Use default, included texture else puts("External texture loaded!"); int fields_x = 16; int fields_y = 16; int field_width = terrain_current->width / fields_x; int field_height = terrain_current->height / fields_y; //Give grass and leaves color const RGB green = { 0.5f, 0.8f, 0.3f }; makeColor(green, *terrain_current, 0, 0, field_width, field_height); makeColor(green, *terrain_current, 5 * field_width, 3 * field_height, field_width, field_height); makeColor(green, *terrain_current, 4 * field_width, 3 * field_height, field_width, field_height); //Also redstone drawTexture(*terrain_current, *terrain_current, 4 * field_width, 10 * field_height, field_width, field_height, 4 * field_width, 11 * field_height, field_width, field_height); const RGB red = { 0.9f, 0.1f, 0.1f }; makeColor(red, *terrain_current, 4 * field_width, 11 * field_height, field_width, field_height); //And redstone switches drawTexture(*terrain_current, *terrain_current, 0 * field_width, 6 * field_height, field_width, field_height, 0 * field_width, 7 * field_height, field_width, field_height); const RGB red_tint = { 1.0f, 0.8f, 0.8f }; makeColor(red_tint, *terrain_current, 0 * field_width, 7 * field_height, field_width, field_height); if(terrain_current->width == 256 && terrain_current->height == 256) terrain_resized = terrain_current; else terrain_resized = resizeTexture(*terrain_current, 256, 256); for(int y = 0; y < fields_y; y++) for(int x = 0; x < fields_x; x++) { //+1 and -2 to work around GLFix inaccuracies resulting in rounding errors TerrainAtlasEntry tea = terrain_atlas[x][y] = {textureArea(x * field_width + 1, y * field_height + 1, field_width - 2, field_height - 2), textureArea(x * 16, y * 16, 16, 16) }; BLOCK_TEXTURE bt = texture_atlas[y][x]; if(bt.sides == 0) continue; if(bt.sides & BLOCK_BOTTOM_BIT) block_textures[bt.block][BLOCK_BOTTOM] = tea; if(bt.sides & BLOCK_TOP_BIT) block_textures[bt.block][BLOCK_TOP] = tea; if(bt.sides & BLOCK_LEFT_BIT) block_textures[bt.block][BLOCK_LEFT] = tea; if(bt.sides & BLOCK_RIGHT_BIT) block_textures[bt.block][BLOCK_RIGHT] = tea; if(bt.sides & BLOCK_FRONT_BIT) block_textures[bt.block][BLOCK_FRONT] = tea; if(bt.sides & BLOCK_BACK_BIT) block_textures[bt.block][BLOCK_BACK] = tea; } //Slight hack, you can't assign a texture to multiple blocks block_textures[BLOCK_GRASS][BLOCK_BOTTOM] = block_textures[BLOCK_DIRT][BLOCK_BOTTOM]; //Prerender four times the same texture to speed up drawing, see terrain.h const BLOCK_TEXTURE quad_textures[] = { ALL(BLOCK_DIRT), SID(BLOCK_GRASS), TOP(BLOCK_GRASS), ALL(BLOCK_STONE), ALL(BLOCK_SAND), SID(BLOCK_WOOD), ALL(BLOCK_PLANKS_NORMAL), ALL(BLOCK_LEAVES) }; terrain_quad = newTexture(field_width * 2 * (sizeof(quad_textures)/sizeof(*quad_textures)), field_height * 2); for(BLOCK b = 0; b <= BLOCK_NORMAL_LAST; b++) for(uint8_t s = 0; s <= BLOCK_SIDE_LAST; s++) quad_block_textures[b][s].has_quad = false; unsigned int x = 0; for(BLOCK_TEXTURE bt : quad_textures) { TextureAtlasEntry *tae = nullptr; if(bt.sides & BLOCK_BOTTOM_BIT) tae = &block_textures[bt.block][BLOCK_BOTTOM].current; if(bt.sides & BLOCK_TOP_BIT) tae = &block_textures[bt.block][BLOCK_TOP].current; if(bt.sides & BLOCK_LEFT_BIT) tae = &block_textures[bt.block][BLOCK_LEFT].current; if(bt.sides & BLOCK_RIGHT_BIT) tae = &block_textures[bt.block][BLOCK_RIGHT].current; if(bt.sides & BLOCK_FRONT_BIT) tae = &block_textures[bt.block][BLOCK_FRONT].current; if(bt.sides & BLOCK_BACK_BIT) tae = &block_textures[bt.block][BLOCK_BACK].current; if(!tae) { printf("Block %d has no texture!\n", bt.block); continue; } //- 1 to reverse the workaround above. Yes, I hate myself for this. drawTexture(*terrain_current, *terrain_quad, tae->left - 1, tae->top - 1, field_width, field_height, x, 0, field_width, field_height); drawTexture(*terrain_current, *terrain_quad, tae->left - 1, tae->top - 1, field_width, field_height, x + field_width, 0, field_width, field_height); drawTexture(*terrain_current, *terrain_quad, tae->left - 1, tae->top - 1, field_width, field_height, x+ field_width, field_height, field_width, field_height); drawTexture(*terrain_current, *terrain_quad, tae->left - 1, tae->top - 1, field_width, field_height, x, field_height, field_width, field_height); //Get an average color of the block RGB sum; for(unsigned int tex_x = tae->left - 1; tex_x <= tae->right; ++tex_x) for(unsigned int tex_y = tae->top - 1; tex_y <= tae->bottom; ++tex_y) { RGB rgb = rgbColor(terrain_current->bitmap[tex_x + tex_y*terrain_current->width]); sum.r += rgb.r; sum.g += rgb.g; sum.b += rgb.b; } int pixels = field_width * field_height; sum.r /= pixels; sum.g /= pixels; sum.b /= pixels; const COLOR darker = colorRGB(sum.r / GLFix(1.5f), sum.g / GLFix(1.5f), sum.b / GLFix(1.5f)); //And add the workaround here again.. TerrainQuadEntry tqe = { true, textureArea(x + 1, 1, field_width * 2 - 2, field_height * 2 - 2), colorRGB(sum), darker }; if(bt.sides & BLOCK_BOTTOM_BIT) quad_block_textures[bt.block][BLOCK_BOTTOM] = tqe; if(bt.sides & BLOCK_TOP_BIT) quad_block_textures[bt.block][BLOCK_TOP] = tqe; if(bt.sides & BLOCK_LEFT_BIT) quad_block_textures[bt.block][BLOCK_LEFT] = tqe; if(bt.sides & BLOCK_RIGHT_BIT) quad_block_textures[bt.block][BLOCK_RIGHT] = tqe; if(bt.sides & BLOCK_FRONT_BIT) quad_block_textures[bt.block][BLOCK_FRONT] = tqe; if(bt.sides & BLOCK_BACK_BIT) quad_block_textures[bt.block][BLOCK_BACK] = tqe; x += field_width * 2; } //Part 2 of the hack above quad_block_textures[BLOCK_GRASS][BLOCK_BOTTOM] = quad_block_textures[BLOCK_DIRT][BLOCK_BOTTOM]; if(lcd_type() == SCR_320x240_4) { greyscaleTexture(*terrain_current); greyscaleTexture(*terrain_resized); greyscaleTexture(*terrain_quad); } //Resize the glass texture to 32x32 const TextureAtlasEntry &glass_tex = block_textures[BLOCK_GLASS][BLOCK_FRONT].current; glass_big = newTexture(32, 32); drawTexture(*terrain_current, *glass_big, glass_tex.left - 1, glass_tex.top - 1, field_width, field_height, 0, 0, 32, 32); }