#include "Draw.h"
///vars to add to structs
struct OGL_Texture{
float bw,bh;//blit width/height if non pwr 2 textures
};
struct OGL_Surface : OGL_Texture{
float bw,bh;
};
///Draw Funcs to replace (also replace "GL_TEXTURE_RECTANGLE_NV" with "GL_TEXTURE_2D")
bool IsPowerOfTwo(uint32_t x)
{
return ((x & (x - 1)) == 0);
}
int HighestBit(uint32_t x)
{
if (IsPowerOfTwo(x)){return x;}
uint32_t y = 1<<31;
while (y>x){y=y>>1;}
return y<<1;
}
void OGL_Texture::gen_texture(uint16_t width, uint16_t height, uint8_t *PixData){
if (width==0 || height==0){printf("ERROR! WIDTH OR HEIGHT OF TEXTURE == 0"); exit(1);}
//delete old texture if existing
if (texture_generated && Texture_ID){
glDeleteTextures(1,&Texture_ID);
}
//Power of two texture support
w = width;
h = height;
uint8_t *NewPixData = PixData;
bool todelete = false;
if (!(IsPowerOfTwo(w) && IsPowerOfTwo(h))){
uint32_t new_w = HighestBit(w);
uint32_t new_h = HighestBit(h);
NewPixData = new uint8_t[new_w*new_h*4];
memset(NewPixData,255, new_w*new_h*4);
uint32_t pos1 = 0;
uint32_t pos2 = 0;
for (uint32_t y = 0; y<h; y++){
for (uint32_t x = 0; x<w; x++){
NewPixData[pos1] = PixData[pos2];
NewPixData[pos1+1]= PixData[pos2+1];
NewPixData[pos1+2]= PixData[pos2+2];
NewPixData[pos1+3]= PixData[pos2+3];
pos1+=4;
pos2+=4;
}
pos1+=(new_w-w)*4;
}
width= new_w;
height= new_h;
bw = float(w)/float(new_w);
bh = float(h)/float(new_h);
todelete = true;
}
//generate texture
glGenTextures(1,&Texture_ID);
if (Texture_ID==0){printf("ERROR IN TEXTURE GENERATION! NO DEVICE CONTEXT?"); exit(1);}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture_ID);
//2d texture, level of detail, number of components (3=rgb), w,h, border, byte order, data format, data
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA8, width, height, 0, GL_BGRA,GL_UNSIGNED_BYTE, NewPixData);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glDisable(GL_TEXTURE_2D);
texture_generated = true;
//cleanup
if (todelete){delete [] NewPixData;}
}
///////////////
//OGL Surface//
///////////////
void OGL_Surface::Create_Surface(uint16_t set_w,uint16_t set_h, char set_bpp){
if (set_bpp==24){bpp=3;}
if (set_bpp==32){bpp=4;}
// if surface already exists and width or height change delete old texture
if (texture_generated && (w != set_w || h != set_h)){
glDeleteTextures(1,&Texture_ID);
texture_generated = false;
}
// if surface already exists delete old data
if (PixData != nullptr) {delete [] PixData;}
w = set_w;
h = set_h;
bpp = set_bpp;
PixData = new uint8_t[w*h*bpp];
memset(PixData,255, w*h*bpp);
if (!(IsPowerOfTwo(w) && IsPowerOfTwo(h))){printf("WARNING: non pow two surface, may be slow\n");}
}
void OGL_Surface::gen_texture(){
if (w==0 || h==0){printf("ERROR! WIDTH OR HEIGHT OF SURFACE == 0"); exit(1);}
//Power of two texture support
uint32_t width = w;
uint32_t height= h;
uint8_t *NewPixData = PixData;
bool todelete = false;
if (!(IsPowerOfTwo(w) && IsPowerOfTwo(h))){
uint32_t new_w = HighestBit(w);
uint32_t new_h = HighestBit(h);
NewPixData = new uint8_t[new_w*new_h*4];
memset(NewPixData,255, new_w*new_h*4);
uint32_t pos1 = 0;
uint32_t pos2 = 0;
for (uint32_t y = 0; y<h; y++){
for (uint32_t x = 0; x<w; x++){
NewPixData[pos1] = PixData[pos2];
NewPixData[pos1+1]= PixData[pos2+1];
NewPixData[pos1+2]= PixData[pos2+2];
NewPixData[pos1+3]= PixData[pos2+3];
pos1+=4;
pos2+=4;
}
pos1+=(new_w-w)*4;
}
width= new_w;
height= new_h;
bw = w/new_w;
bh = h/new_h;
todelete = true;
}
//only generate a texture once
if (!texture_generated){
glGenTextures(1,&Texture_ID);
if (Texture_ID==0){printf("ERROR IN TEXTURE GENERATION! NO DEVICE CONTEXT?"); exit(1);}
}
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Texture_ID);
//glTexImage2D respecifies the entire texture, changing its size, deleting the previous data etc.
//only do this if texture doesn't exist or if w/h change
if (!texture_generated){
switch (bpp){
//2d texture, level of detail, number of components (3=rgb), w,h, border, byte order, data format, data
case 3: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, NewPixData); break;
case 4: glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA,GL_UNSIGNED_BYTE, NewPixData); break;
}
}
//glTexSubImage2D only modifies pixel data within the texture.
//do this when pixels need to be updated
else{
switch (bpp){
//2d texture, level of detail, xoffset,yoffset, w,h, byte order, data format, data
case 3: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGR, GL_UNSIGNED_BYTE, NewPixData); break;
case 4: glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA,GL_UNSIGNED_BYTE, NewPixData); break;
}
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glDisable(GL_TEXTURE_2D);
texture_generated = true;
//cleanup
if (todelete){delete [] NewPixData;}
}
//BLIT//
////////
//glBlendFunc(source_blend, dst_blend)
//GL_ZERO colour is ignored
//GL_ONE full colour is taken into addition
//GL_(DST/SRC)_COLOR colour is multiplied by (DST/SRC) color
//GL_ONE_MINUS_(DST/SRC)_COLOR colour is multiplied by inverted (DST/SRC) color
//GL_(DST/SRC)_ALPHA colour is multiplied by (DST/SRC) alpha value
//GL_ONE_MINUS_(DST/SRC)_ALPHA colour is multiplied by inverted (DST/SRC) alpha value
//overall colour (GL_SRC_ALPHA, GL_ONE) -addative- = (r1*a1,g1*a1,b1*a1)+(r2,g2,b2)
void DrawImage(OGL_Texture *Texture, int dx, int dy, float rot,float scale_x,float scale_y,float alpha,int options){
if (options & IMG_HFLIP){dx+=Texture->w; scale_x=-1;}
if (options & IMG_VFLIP){dy+=Texture->h; scale_y=-1;}
glLoadIdentity();
glTranslatef(dx, dy, 0.0);
if (scale_x!=1 && scale_y!=1){glScaled(scale_x, scale_y, 0);}
if (rot!=0){
int tmpw = Texture->w/2;
int tmph = Texture->h/2;
glTranslatef(tmpw, tmph, 0.0);
glRotatef(rot, 0, 0, 1.0);
glTranslatef(-tmpw, -tmph, 0.0);
}
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
//additive blending - gray + gray = white
if (options &= IMG_ADD_BLEND){glBlendFunc(GL_SRC_ALPHA, GL_ONE);}
//regular alpha blending - gray + gray = gray
else{glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);}
//blit
glColor4f(1.0f, 1.0f, 1.0f, alpha);
glBindTexture(GL_TEXTURE_2D, Texture->Texture_ID);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex2d(0, 0);
glTexCoord2f(Texture->bw,0);
glVertex2d(Texture->w, 0);
glTexCoord2f(Texture->bw,Texture->bh);
glVertex2d(Texture->w, Texture->h);
glTexCoord2f(0,Texture->bh);
glVertex2d(0, Texture->h);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glLoadIdentity();
}
void DrawSubImage(OGL_Texture *Texture, int sx, int sy, int sw, int sh, int dx, int dy, float rot,float scale_x,float scale_y,float alpha,int options){
float tex_coord_x1 = (float)sx/(float)Texture->w;
float tex_coord_y1 = (float)sy/(float)Texture->h;
float tex_coord_x2 = tex_coord_x1+((float)sw/(float)Texture->w);
float tex_coord_y2 = tex_coord_y1+((float)sh/(float)Texture->h);
tex_coord_x1 *= Texture->bw;
tex_coord_y1 *= Texture->bh;
tex_coord_x2 *= Texture->bw;
tex_coord_y2 *= Texture->bh;
if (options & IMG_HFLIP){dx+=Texture->w; scale_x=-1;}
if (options & IMG_VFLIP){dy+=Texture->h; scale_y=-1;}
glLoadIdentity();
glTranslatef(dx, dy, 0.0);
if (scale_x!=1 && scale_y!=1){glScaled(scale_x, scale_y, 0);}
if (rot!=0){
int tmpw = Texture->w/2;
int tmph = Texture->h/2;
glTranslatef(tmpw, tmph, 0.0);
glRotatef(rot, 0, 0, 1.0);
glTranslatef(-tmpw, -tmph, 0.0);
}
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
//additive blending - gray + gray = white
if (options &= IMG_ADD_BLEND){glBlendFunc(GL_SRC_ALPHA, GL_ONE);}
//regular alpha blending - gray + gray = gray
else{glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);}
//blit
glColor4f(1.0,1.0,1.0,alpha);
glBindTexture(GL_TEXTURE_2D, Texture->Texture_ID);
glBegin(GL_QUADS);
glTexCoord2f(tex_coord_x1,tex_coord_y1);
glVertex2d(0, 0);
glTexCoord2f(tex_coord_x2,tex_coord_y1);
glVertex2d(sw, 0);
glTexCoord2f(tex_coord_x2,tex_coord_y2);
glVertex2d(sw, sh);
glTexCoord2f(tex_coord_x1,tex_coord_y2);
glVertex2d(0, sh);
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glLoadIdentity();
}