bool PaletteEntryPanel::generateColormaps() { if (!entry || !entry->getParent() || ! palettes[0]) return false; MemChunk mc; SImage img; MemChunk imc; mc.reSize(34*256); mc.seek(0, SEEK_SET); imc.reSize(34*256*4); imc.seek(0, SEEK_SET); uint8_t rgba[4]; rgba[3] = 255; rgba_t rgb; float grey; // Generate 34 maps: the first 32 for diminishing light levels, // the 33th for the inverted grey map used by invulnerability. // The 34th colormap remains empty and black. for (size_t l = 0; l < 34; ++l) { for (size_t c = 0; c < 256; ++c) { rgb = palettes[0]->colour(c); if (l < 32) { // Generate light maps DIMINISH(rgb.r, l); DIMINISH(rgb.g, l); DIMINISH(rgb.b, l); #if (0) } else if (l == GREENMAP) { // Point of mostly useless trivia: the green "light amp" colormap in the Press Release beta // have colors that, on average, correspond to a bit less than (R*75/256, G*225/256, B*115/256) #endif } else if (l == GRAYMAP) { // Generate inverse map grey = ((float)rgb.r/256.0 * col_greyscale_r) + ((float)rgb.g/256.0 * col_greyscale_g) + ((float)rgb.b/256.0 * col_greyscale_b); grey = 1.0 - grey; // Clamp value: with Id Software's values, the sum is greater than 1.0 (0.299+0.587+0.144=1.030) // This means the negation above can give a negative value (for example, with RGB values of 247 or more), // which will not be converted correctly to unsigned 8-bit int in the rgba_t struct. if (grey < 0.0) grey = 0; rgb.r = rgb.g = rgb.b = grey*255; } else { // Fill with 0 rgb = palettes[0]->colour(0); } rgba[0] = rgb.r; rgba[1] = rgb.g; rgba[2] = rgb.b; imc.write(&rgba, 4); mc[(256*l)+c] = palettes[0]->nearestColour(rgb); } } #if 0 // Create truecolor image uint8_t* imd = new uint8_t[256*34*4]; memcpy(imd, imc.getData(), 256*34*4); img.setImageData(imd, 256, 34, RGBA); // imd will be freed by img's destructor ArchiveEntry* tcolormap; string name = entry->getName(true) + "-tcm.png"; tcolormap = new ArchiveEntry(name); if (tcolormap) { entry->getParent()->addEntry(tcolormap); SIFormat::getFormat("png")->saveImage(img, tcolormap->getMCData()); EntryType::detectEntryType(tcolormap); } #endif // Now override or create new entry ArchiveEntry* colormap; colormap = entry->getParent()->getEntry("COLORMAP", true); bool preexisting = colormap != NULL; if (!colormap) { // We need to create this entry colormap = new ArchiveEntry("COLORMAP.lmp", 34*256); } if (!colormap) return false; colormap->importMemChunk(mc); if (!preexisting) { entry->getParent()->addEntry(colormap); } return true; }
/* MapPreviewCanvas::createImage * Draws the map in an image * TODO: Factorize code with normal draw() and showMap() functions. * TODO: Find a way to generate an arbitrary-sized image through * tiled rendering. *******************************************************************/ void MapPreviewCanvas::createImage(ArchiveEntry& ae, int width, int height) { // Find extents of map mep_vertex_t m_min(999999.0, 999999.0); mep_vertex_t m_max(-999999.0, -999999.0); for (unsigned a = 0; a < verts.size(); a++) { if (verts[a].x < m_min.x) m_min.x = verts[a].x; if (verts[a].x > m_max.x) m_max.x = verts[a].x; if (verts[a].y < m_min.y) m_min.y = verts[a].y; if (verts[a].y > m_max.y) m_max.y = verts[a].y; } double mapwidth = m_max.x - m_min.x; double mapheight = m_max.y - m_min.y; if (width == 0) width = -5; if (height == 0) height = -5; if (width < 0) width = mapwidth / abs(width); if (height < 0) height = mapheight / abs(height); // Setup colours rgba_t col_save_background = ColourConfiguration::getColour("map_image_background"); rgba_t col_save_line_1s = ColourConfiguration::getColour("map_image_line_1s"); rgba_t col_save_line_2s = ColourConfiguration::getColour("map_image_line_2s"); rgba_t col_save_line_special = ColourConfiguration::getColour("map_image_line_special"); rgba_t col_save_line_macro = ColourConfiguration::getColour("map_image_line_macro"); // Setup OpenGL rigmarole GLuint texID, fboID; if (GLEW_ARB_framebuffer_object) { glGenTextures(1, &texID); glBindTexture(GL_TEXTURE_2D, texID); // We don't use mipmaps, but OpenGL will refuse to attach // the texture to the framebuffer if they are not present glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindTexture(GL_TEXTURE_2D, 0); glGenFramebuffersEXT(1, &fboID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texID, 0); GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); } glViewport(0, 0, width, height); // Setup the screen projection glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, 0, height, -1, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // Clear glClearColor(((double)col_save_background.r)/255.f, ((double)col_save_background.g)/255.f, ((double)col_save_background.b)/255.f, ((double)col_save_background.a)/255.f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); // Translate to inside of pixel (otherwise inaccuracies can occur on certain gl implementations) if (OpenGL::accuracyTweak()) glTranslatef(0.375f, 0.375f, 0); // Zoom/offset to show full map // Offset to center of map offset_x = m_min.x + (mapwidth * 0.5); offset_y = m_min.y + (mapheight * 0.5); // Zoom to fit whole map double x_scale = ((double)width) / mapwidth; double y_scale = ((double)height) / mapheight; zoom = MIN(x_scale, y_scale); zoom *= 0.95; // Translate to middle of canvas glTranslated(width>>1, height>>1, 0); // Zoom glScaled(zoom, zoom, 1); // Translate to offset glTranslated(-offset_x, -offset_y, 0); // Setup drawing glDisable(GL_TEXTURE_2D); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glLineWidth(map_image_thickness); glEnable(GL_LINE_SMOOTH); // Draw lines for (unsigned a = 0; a < lines.size(); a++) { mep_line_t line = lines[a]; // Check ends if (line.v1 >= verts.size() || line.v2 >= verts.size()) continue; // Get vertices mep_vertex_t v1 = verts[lines[a].v1]; mep_vertex_t v2 = verts[lines[a].v2]; // Set colour if (line.special) OpenGL::setColour(col_save_line_special); else if (line.macro) OpenGL::setColour(col_save_line_macro); else if (line.twosided) OpenGL::setColour(col_save_line_2s); else OpenGL::setColour(col_save_line_1s); // Draw line glBegin(GL_LINES); glVertex2d(v1.x, v1.y); glVertex2d(v2.x, v2.y); glEnd(); } glLineWidth(1.0f); glDisable(GL_LINE_SMOOTH); uint8_t* ImageBuffer = new uint8_t[width * height * 4]; glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, ImageBuffer); if (GLEW_ARB_framebuffer_object) { glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteTextures( 1, &texID ); glDeleteFramebuffersEXT( 1, &fboID ); } SImage img; img.setImageData(ImageBuffer, width, height, RGBA); img.mirror(true); MemChunk mc; SIFormat::getFormat("png")->saveImage(img, mc); ae.importMemChunk(mc); }