<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 <NAME>
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"
#include <string>
#include "bzfio.h"
#include "bzfgl.h"
#include "OpenGLTexture.h"
#include "OpenGLGState.h"

//
// OpenGLTexture::Rep
//

const GLenum		OpenGLTexture::minifyFilter[] = {
				GL_NEAREST,
				GL_NEAREST,
				GL_LINEAR,
				GL_NEAREST_MIPMAP_NEAREST,
				GL_LINEAR_MIPMAP_NEAREST,
				GL_NEAREST_MIPMAP_LINEAR,
				GL_LINEAR_MIPMAP_LINEAR
			};
const GLenum		OpenGLTexture::magnifyFilter[] = {
				GL_NEAREST,
				GL_NEAREST,
				GL_LINEAR,
				GL_NEAREST,
				GL_LINEAR,
				GL_NEAREST,
				GL_LINEAR
			};
const char*		OpenGLTexture::configFilterNames[] = {
				"no",
				"nearest",
				"linear",
				"nearestmipmapnearest",
				"linearmipmapnearest",
				"nearestmipmaplinear",
				"linearmipmaplinear"
};


//
// OpenGLTexture
//

const int OpenGLTexture::filterCount = Max + 1;
OpenGLTexture::Filter OpenGLTexture::maxFilter = Default;


OpenGLTexture::OpenGLTexture(int _width, int _height, const GLvoid* pixels,
			     Filter _filter, bool _repeat, int _internalFormat) :
			   width(_width), height(_height)
{
  alpha = false;
  repeat = _repeat;
  internalFormat = _internalFormat;
  filter = _filter;
  list = INVALID_GL_TEXTURE_ID;

  // get internal format if not provided
  if (internalFormat == 0)
    internalFormat = getBestFormat(width, height, pixels);

  // copy/scale the original texture image
  setupImage((const GLubyte*)pixels);

  // build and bind the GL texture
  initContext();

  // watch for context recreation
  OpenGLGState::registerContextInitializer(static_freeContext,
					   static_initContext, (void*)this);
}


OpenGLTexture::~OpenGLTexture()
{
  OpenGLGState::unregisterContextInitializer(static_freeContext,
					     static_initContext, (void*)this);
  delete[] imageMemory;

  freeContext();
  return;
}


void OpenGLTexture::static_freeContext(void *that)
{
  ((OpenGLTexture*) that)->freeContext();
}


void OpenGLTexture::static_initContext(void *that)
{
  ((OpenGLTexture*) that)->initContext();
}


void OpenGLTexture::freeContext()
{
  // glDeleteTextures should set binding to 0 by itself when the texture
  //  is in use, but some stacks (Linux/glx/matrox) are broken, so play it safe
  glBindTexture(GL_TEXTURE_2D, 0);

  if (list != INVALID_GL_TEXTURE_ID) {
    glDeleteTextures(1, &list);
    list = INVALID_GL_TEXTURE_ID;
  }
  return;
}


void OpenGLTexture::initContext()
{
  // make texture map object/list
  glGenTextures(1, &list);

  // now make texture map display list (compute all mipmaps, if requested).
  // compute next mipmap from current mipmap to save time.
  setFilter(filter);
  glBindTexture(GL_TEXTURE_2D, list);
  gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat,
		    scaledWidth, scaledHeight,
		    GL_RGBA, GL_UNSIGNED_BYTE, image);
  glBindTexture(GL_TEXTURE_2D, 0);

  return;
}


bool OpenGLTexture::setupImage(const GLubyte* pixels)
{
  // align to a 2^N value
  scaledWidth = 1;
  scaledHeight = 1;
  while (scaledWidth < width) {
    scaledWidth <<= 1;
  }
  while (scaledHeight < height) {
    scaledHeight <<= 1;
  }

  // get minimum valid size for texture (boost to 2^m x 2^n)
  GLint maxTextureSize;
  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);

  // hard limit, some drivers have problems with sizes greater
  // then this (espeically if you are using glTexSubImage2D)
  const GLint bzMaxTexSize = 512;
  if (maxTextureSize > bzMaxTexSize) {
    maxTextureSize = bzMaxTexSize;
  }

  // clamp to the maximum size
  if (scaledWidth > maxTextureSize) {
    scaledWidth = maxTextureSize;
  }
  if (scaledHeight > maxTextureSize) {
    scaledHeight = maxTextureSize;
  }

  // NOTE: why these are 4-byte aligned is beyond me...

  // copy the data into a 4-byte aligned buffer
  GLubyte* unaligned = new GLubyte[4 * width * height + 4];
  GLubyte* aligned = (GLubyte*)(((unsigned long)unaligned & ~3) + 4);
  ::memcpy(aligned, pixels, 4 * width * height);

  // scale the image if required
  if ((scaledWidth != width) || (scaledHeight != height)) {
    GLubyte* unalignedScaled = new GLubyte[4 * scaledWidth * scaledHeight + 4];
    GLubyte* alignedScaled = (GLubyte*)(((unsigned long)unalignedScaled & ~3) + 4);<commit_msg>for some reason glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); is returning a huge negative number. If it is set max to 512, which is bz's max anyway. Not sure why this is happening.<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 <NAME>
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "common.h"
#include <string>
#include "bzfio.h"
#include "bzfgl.h"
#include "OpenGLTexture.h"
#include "OpenGLGState.h"

//
// OpenGLTexture::Rep
//

const GLenum		OpenGLTexture::minifyFilter[] = {
				GL_NEAREST,
				GL_NEAREST,
				GL_LINEAR,
				GL_NEAREST_MIPMAP_NEAREST,
				GL_LINEAR_MIPMAP_NEAREST,
				GL_NEAREST_MIPMAP_LINEAR,
				GL_LINEAR_MIPMAP_LINEAR
			};
const GLenum		OpenGLTexture::magnifyFilter[] = {
				GL_NEAREST,
				GL_NEAREST,
				GL_LINEAR,
				GL_NEAREST,
				GL_LINEAR,
				GL_NEAREST,
				GL_LINEAR
			};
const char*		OpenGLTexture::configFilterNames[] = {
				"no",
				"nearest",
				"linear",
				"nearestmipmapnearest",
				"linearmipmapnearest",
				"nearestmipmaplinear",
				"linearmipmaplinear"
};


//
// OpenGLTexture
//

const int OpenGLTexture::filterCount = Max + 1;
OpenGLTexture::Filter OpenGLTexture::maxFilter = Default;


OpenGLTexture::OpenGLTexture(int _width, int _height, const GLvoid* pixels,
			     Filter _filter, bool _repeat, int _internalFormat) :
			   width(_width), height(_height)
{
  alpha = false;
  repeat = _repeat;
  internalFormat = _internalFormat;
  filter = _filter;
  list = INVALID_GL_TEXTURE_ID;

  // get internal format if not provided
  if (internalFormat == 0)
    internalFormat = getBestFormat(width, height, pixels);

  // copy/scale the original texture image
  setupImage((const GLubyte*)pixels);

  // build and bind the GL texture
  initContext();

  // watch for context recreation
  OpenGLGState::registerContextInitializer(static_freeContext,
					   static_initContext, (void*)this);
}


OpenGLTexture::~OpenGLTexture()
{
  OpenGLGState::unregisterContextInitializer(static_freeContext,
					     static_initContext, (void*)this);
  delete[] imageMemory;

  freeContext();
  return;
}


void OpenGLTexture::static_freeContext(void *that)
{
  ((OpenGLTexture*) that)->freeContext();
}


void OpenGLTexture::static_initContext(void *that)
{
  ((OpenGLTexture*) that)->initContext();
}


void OpenGLTexture::freeContext()
{
  // glDeleteTextures should set binding to 0 by itself when the texture
  //  is in use, but some stacks (Linux/glx/matrox) are broken, so play it safe
  glBindTexture(GL_TEXTURE_2D, 0);

  if (list != INVALID_GL_TEXTURE_ID) {
    glDeleteTextures(1, &list);
    list = INVALID_GL_TEXTURE_ID;
  }
  return;
}


void OpenGLTexture::initContext()
{
  // make texture map object/list
  glGenTextures(1, &list);

  // now make texture map display list (compute all mipmaps, if requested).
  // compute next mipmap from current mipmap to save time.
  setFilter(filter);
  glBindTexture(GL_TEXTURE_2D, list);
  gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat,
		    scaledWidth, scaledHeight,
		    GL_RGBA, GL_UNSIGNED_BYTE, image);
  glBindTexture(GL_TEXTURE_2D, 0);

  return;
}


bool OpenGLTexture::setupImage(const GLubyte* pixels)
{
  // align to a 2^N value
  scaledWidth = 1;
  scaledHeight = 1;
  while (scaledWidth < width) {
    scaledWidth <<= 1;
  }
  while (scaledHeight < height) {
    scaledHeight <<= 1;
  }

  // get minimum valid size for texture (boost to 2^m x 2^n)
  GLint maxTextureSize;
  glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);

  // hard limit, some drivers have problems with sizes greater
  // then this (espeically if you are using glTexSubImage2D)
  const GLint bzMaxTexSize = 512;
  if ((maxTextureSize < 0) || (maxTextureSize > bzMaxTexSize)) {
    maxTextureSize = bzMaxTexSize;
  }

  // clamp to the maximum size
  if (scaledWidth > maxTextureSize) {
    scaledWidth = maxTextureSize;
  }
  if (scaledHeight > maxTextureSize) {
    scaledHeight = maxTextureSize;
  }

  // NOTE: why these are 4-byte aligned is beyond me...

  // copy the data into a 4-byte aligned buffer
  GLubyte* unaligned = new GLubyte[4 * width * height + 4];
  GLubyte* aligned = (GLubyte*)(((unsigned long)unaligned & ~3) + 4);
  ::memcpy(aligned, pixels, 4 * width * height);

  // scale the image if required
  if ((scaledWidth != width) || (scaledHeight != height)) {
    GLubyte* unalignedScaled = new GLubyte[4 * scaledWidth * scaledHeight + 4];
    GLubyte* alignedScaled = (GLubyte*)(((unsigned long)unalignedScaled & ~3) + 4);
{'fraction_non_alphanumeric': 0.10654086716845118, 'fraction_numerical': 0.009328951553058412, 'mean_word_length': 3.9496327387198322, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4979544', 'n_tokens_mistral': 3462, 'n_tokens_neox': 3144, 'n_words': 843}