diff --git a/include/glkos.h b/include/glkos.h index ed60587..a6602c0 100644 --- a/include/glkos.h +++ b/include/glkos.h @@ -1,5 +1,4 @@ -#ifndef GLKOS_H -#define GLKOS_H +#pragma once #include "gl.h" @@ -40,4 +39,3 @@ GLAPI void APIENTRY glKosSwapBuffers(); __END_DECLS -#endif // GLKOS_H diff --git a/samples/Makefile b/samples/Makefile index 8854101..eabf377 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -19,3 +19,4 @@ all: $(KOS_MAKE) -C zclip_trianglestrip all $(KOS_MAKE) -C terrain all $(KOS_MAKE) -C quadmark all + $(KOS_MAKE) -C multitexture_arrays all diff --git a/samples/multitexture_arrays/Makefile b/samples/multitexture_arrays/Makefile new file mode 100644 index 0000000..2134157 --- /dev/null +++ b/samples/multitexture_arrays/Makefile @@ -0,0 +1,29 @@ +TARGET = multitexture_arrays.elf +OBJS = main.o pvr-texture.o + +all: rm-elf $(TARGET) + +include $(KOS_BASE)/Makefile.rules + +clean: + -rm -f $(TARGET) $(OBJS) romdisk.* + +rm-elf: + -rm -f $(TARGET) romdisk.* + +$(TARGET): $(OBJS) romdisk.o + $(KOS_CC) $(KOS_CFLAGS) $(KOS_LDFLAGS) -o $(TARGET) $(KOS_START) \ + $(OBJS) romdisk.o $(OBJEXTRA) -lm -lkosutils $(KOS_LIBS) + +romdisk.img: + $(KOS_GENROMFS) -f romdisk.img -d romdisk -v + +romdisk.o: romdisk.img + $(KOS_BASE)/utils/bin2o/bin2o romdisk.img romdisk romdisk.o + +run: $(TARGET) + $(KOS_LOADER) $(TARGET) + +dist: + rm -f $(OBJS) romdisk.o romdisk.img + $(KOS_STRIP) $(TARGET) diff --git a/samples/multitexture_arrays/main.c b/samples/multitexture_arrays/main.c new file mode 100644 index 0000000..e235022 --- /dev/null +++ b/samples/multitexture_arrays/main.c @@ -0,0 +1,121 @@ +/* + KallistiOS 2.0.0 + + main.c + (c)2014 Josh Pearson + + Open GL Multi-Texture example using Vertex Array Submission. +*/ + +#include + +#include "gl.h" +#include "glu.h" +#include "glkos.h" +#include "glext.h" + +/* Load a PVR texture - located in pvr-texture.c */ +extern GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap); + +GLfloat VERTEX_ARRAY[4 * 3] = { -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + -1.0f, -1.0f, 0.0f + }; + +GLfloat TEXCOORD_ARRAY[4 * 2] = { 0, 0, + 1, 0, + 1, 1, + 0, 1 + }; + +GLuint ARGB_ARRAY[4 * 1] = { 0xFFFF0000, 0xFF0000FF, 0xFF00FF00, 0xFFFFFF00 }; + + +/* Multi-Texture Example using Open GL Vertex Buffer Submission. */ +void RenderCallback(GLuint texID0, GLuint texID1) { + glLoadIdentity(); + glTranslatef(0.0f, 0.0f, -3.0f); + + /* Enable Client States for OpenGL Arrays Submission */ + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + /* Bind texture to GL_TEXTURE0_ARB and set texture parameters */ + glActiveTextureARB(GL_TEXTURE0_ARB); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texID0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FILTER, GL_LINEAR); + + /* Bind multi-texture to GL_TEXTURE1_ARB and set texture parameters */ + glActiveTextureARB(GL_TEXTURE1_ARB); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texID1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FILTER, GL_LINEAR); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + /* Set Blending Mode */ + glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA); + + /* Bind texture coordinates to GL_TEXTURE0_ARB */ + glTexCoordPointer(2, GL_FLOAT, 0, TEXCOORD_ARRAY); + + /* Bind texture coordinates to GL_TEXTURE1_ARB */ + glClientActiveTextureARB(GL_TEXTURE1_ARB); + glTexCoordPointer(2, GL_FLOAT, 0, TEXCOORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0_ARB); + + /* Bind the Color Array */ + glColorPointer(1, GL_UNSIGNED_INT, 0, ARGB_ARRAY); + + /* Bind the Vertex Array */ + glVertexPointer(3, GL_FLOAT, 0, VERTEX_ARRAY); + + /* Render the Vertices as Indexed Arrays using glDrawArrays */ + glDrawArrays(GL_QUADS, 0, 4); + + /* Disable GL_TEXTURE1 */ + glActiveTextureARB(GL_TEXTURE1_ARB); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + /* Make sure to set glActiveTexture back to GL_TEXTURE0_ARB when finished */ + glActiveTextureARB(GL_TEXTURE0_ARB); + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + /* Disable Vertex, Color and Texture Coord Arrays */ + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); +} + +extern uint8 romdisk[]; +KOS_INIT_ROMDISK(romdisk); + +int main(int argc, char **argv) { + /* Notice we do not init the PVR here, that is handled by Open GL */ + glKosInit(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(45.0f, 640.0f / 480.0f, 0.1f, 100.0f); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + /* Load two PVR textures to OpenGL */ + GLuint texID0 = glTextureLoadPVR("/rd/wp001vq.pvr", 0, 0); + GLuint texID1 = glTextureLoadPVR("/rd/FlareWS_256.pvr", 0, 0); + + while(1) { + /* Draw the "scene" */ + RenderCallback(texID0, texID1); + + /* Finish the frame - Notice there is no glKosBegin/FinshFrame */ + glKosSwapBuffers(); + } + + return 0; +} + diff --git a/samples/multitexture_arrays/pvr-texture.c b/samples/multitexture_arrays/pvr-texture.c new file mode 100644 index 0000000..66b16d7 --- /dev/null +++ b/samples/multitexture_arrays/pvr-texture.c @@ -0,0 +1,175 @@ +/* + KallistiOS 2.0.0 + + pvr-texture.c + (c)2014 Josh PH3NOM Pearson + + Load A PVR Texture to the PVR using Open GL +*/ + +#include + +#include "gl.h" +#include "glu.h" +#include "glkos.h" +#include "glext.h" + +#define PVR_HDR_SIZE 0x20 +#define MAX(x, y) ((x > y) ? x : y) + +static GLuint PVR_TextureHeight(unsigned char *HDR); +static GLuint PVR_TextureWidth(unsigned char *HDR); +static GLuint PVR_TextureFormat(unsigned char *HDR); + +static GLuint _glGetMipmapLevelCount(GLuint width, GLuint height) { + return 1 + floor(log2(MAX(width, height))); +} + +static GLuint _glGetMipmapDataSize(GLuint width, GLuint height) { + GLuint size = 0; + + GLuint i = 0; + + for(; i < _glGetMipmapLevelCount(width, height); ++i) { + size += (width * height * 2); + + if(width > 1) { + width /= 2; + } + + if(height > 1) { + height /= 2; + } + } + + return size; +} + +/* Load a PVR texture file into memory, and then bind the texture to Open GL. + fname is the name of the PVR texture file to be opened and read. + isMipMapped should be passed as 1 if the texture contains MipMap levels, 0 otherwise. + glMipMap should be passed as 1 if Open GL should calculate the Mipmap levels, 0 otherwise */ +GLuint glTextureLoadPVR(char *fname, unsigned char isMipMapped, unsigned char glMipMap) { + FILE *tex = NULL; + uint16 *TEX0 = NULL; + uint8 HDR[PVR_HDR_SIZE]; + GLuint texID, texSize, texW, texH, texFormat; + + /* Open the PVR texture file, and get its file size */ + tex = fopen(fname, "rb"); + + if(tex == NULL) { + printf("FILE READ ERROR: %s\n", fname); + + while(1); + } + + fseek(tex, 0, SEEK_END); + texSize = ftell(tex) - PVR_HDR_SIZE; + fseek(tex, 0, SEEK_SET); + + /* Read in the PVR texture file header */ + fread(HDR, 1, PVR_HDR_SIZE, tex); + + /* Extract some information from the PVR texture file header */ + texW = PVR_TextureWidth(HDR); + texH = PVR_TextureHeight(HDR); + texFormat = PVR_TextureFormat(HDR); + + /* Allocate Some Memory for the texture. If we are using Open GL to build the MipMap, + we need to allocate enough space to hold the MipMap texture levels. */ + if(!isMipMapped && glMipMap) + TEX0 = malloc(_glGetMipmapDataSize(texW, texH)); + else + TEX0 = malloc(texSize); + + fread(TEX0, 1, texSize, tex); /* Read in the PVR texture data */ + + /* Generate and bind a texture as normal for Open GL */ + glGenTextures(1, &texID); + glBindTexture(GL_TEXTURE_2D, texID); + + if(texFormat != GL_UNSIGNED_SHORT_5_6_5) + glCompressedTexImage2DARB(GL_TEXTURE_2D, + 0, + texFormat, + texW, + texH, + 0, + texSize, + TEX0); + else { + fprintf(stderr, "%x\n", texFormat); + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGB, + texW, texH, + 0, + GL_RGB, + texFormat, + TEX0); + if(!isMipMapped && glMipMap) + glGenerateMipmapEXT(GL_TEXTURE_2D); + } + + free(TEX0); + + return texID; +} + +static GLuint PVR_TextureFormat(unsigned char *HDR) { + GLuint color = (GLuint)HDR[PVR_HDR_SIZE - 8]; + GLuint format = (GLuint)HDR[PVR_HDR_SIZE - 7]; + + GLboolean twiddled = format == 0x01; + GLboolean compressed = (format == 0x10 || format == 0x03); + + if(compressed) { + if(twiddled) { + switch(color) { + case 0x0: { + return GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; + } break; + case 0x01: { + return GL_COMPRESSED_RGB_565_VQ_TWID_KOS; + } break; + case 0x02: { + return GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; + } + break; + default: + fprintf(stderr, "Invalid texture format"); + return 0; + } + } else { + switch(color) { + case 0: { + return GL_COMPRESSED_ARGB_1555_VQ_KOS; + } break; + case 1: { + return GL_COMPRESSED_RGB_565_VQ_KOS; + } break; + case 2: { + return GL_COMPRESSED_ARGB_4444_VQ_KOS; + } + break; + default: + fprintf(stderr, "Invalid texture format"); + return 0; + } + } + } else { + if(color == 1) { + return GL_UNSIGNED_SHORT_5_6_5; + } + return 0; + } +} + +static GLuint PVR_TextureWidth(unsigned char *HDR) { + return (GLuint)HDR[PVR_HDR_SIZE - 4] | HDR[PVR_HDR_SIZE - 3] << 8; +} + +static GLuint PVR_TextureHeight(unsigned char *HDR) { + return (GLuint)HDR[PVR_HDR_SIZE - 2] | HDR[PVR_HDR_SIZE - 1] << 8; +} diff --git a/samples/multitexture_arrays/romdisk/FlareWS_256.pvr b/samples/multitexture_arrays/romdisk/FlareWS_256.pvr new file mode 100644 index 0000000..d493899 Binary files /dev/null and b/samples/multitexture_arrays/romdisk/FlareWS_256.pvr differ diff --git a/samples/multitexture_arrays/romdisk/PLACEHOLDER b/samples/multitexture_arrays/romdisk/PLACEHOLDER new file mode 100644 index 0000000..e69de29 diff --git a/samples/multitexture_arrays/romdisk/wp001vq.pvr b/samples/multitexture_arrays/romdisk/wp001vq.pvr new file mode 100644 index 0000000..3a6cd19 Binary files /dev/null and b/samples/multitexture_arrays/romdisk/wp001vq.pvr differ