瀏覽代碼

Update to version 1.0.5

Check CHANGELOG for changes
pull/2/head
raysan5 11 年之前
父節點
當前提交
43b13d623b
共有 10 個文件被更改,包括 668 次插入122 次删除
  1. +8
    -0
      CHANGELOG
  2. +0
    -6
      examples/ex06b_logo_anim.c
  3. +2
    -0
      src/audio.c
  4. +23
    -2
      src/core.c
  5. +114
    -107
      src/models.c
  6. +4
    -4
      src/raylib.h
  7. +514
    -0
      src/stb_image_write.h
  8. +1
    -1
      src/text.c
  9. +2
    -2
      src/textures.c
  10. 二進制
      tools/rrem.exe

+ 8
- 0
CHANGELOG 查看文件

@ -6,6 +6,14 @@ Current Release: raylib 1.0.4 (January 2014)
NOTE: Only versions marked as 'Release' are available on release folder, updates are only available as source.
NOTE: Current Release includes all previous updates.
-----------------------------------------------
Update: raylib 1.0.5 (28 January 2014)
-----------------------------------------------
[audio] LoadSound() - Corrected a bug, WAV file was not closed!
[core] GetMouseWheelMove() - Added, check mouse wheel Y movement
[models] LoadHeightmap() - Added, Heightmap can be loaded as a Model
[tool] rREM updated, now supports (partially) drag and drop of files
-----------------------------------------------
Release: raylib 1.0.4 (23 January 2014)
-----------------------------------------------

+ 0
- 6
examples/ex06b_logo_anim.c 查看文件

@ -11,12 +11,6 @@
#include "raylib.h"
// Useful function for fade-ins and fade-outs
Color Fade(Color col, float alpha)
{
return (Color){col.r, col.g, col.b, col.a*alpha};
}
int main()
{
// Initialization

+ 2
- 0
src/audio.c 查看文件

@ -504,6 +504,8 @@ static Wave LoadWAV(char *fileName)
wave.channels = waveFormat.numChannels;
wave.bitsPerSample = waveFormat.bitsPerSample;
fclose(wavFile);
return wave;
}

+ 23
- 2
src/core.c 查看文件

@ -77,6 +77,9 @@ static char currentMouseState[3] = { 0 }; // Required to check if mouse btn pr
static char previousGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
static char currentGamepadState[32] = {0}; // Required to check if gamepad btn pressed/released once
static int previousMouseWheelY = 0;
static int currentMouseWheelY = 0;
//----------------------------------------------------------------------------------
// Other Modules Functions Declaration (required by core)
//----------------------------------------------------------------------------------
@ -89,6 +92,7 @@ extern void UnloadDefaultFont(); // [Module: text] Unloads default f
static void InitGraphicsDevice(); // Initialize Graphics Device (OpenGL stuff)
static void ErrorCallback(int error, const char *description); // GLFW3 Error Callback, runs on GLFW3 error
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); // GLFW3 Srolling Callback, runs on mouse wheel
static void CursorEnterCallback(GLFWwindow* window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area
static void WindowSizeCallback(GLFWwindow* window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void CameraLookAt(Vector3 position, Vector3 target, Vector3 up); // Setup camera view (updates MODELVIEW matrix)
@ -133,6 +137,7 @@ void InitWindowEx(int width, int height, const char* title, bool resizable, cons
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, KeyCallback);
glfwSetScrollCallback(window, ScrollCallback);
glfwSwapInterval(0); // Disables GPU v-sync (if set), so frames are not limited to screen refresh rate (60Hz -> 60 FPS)
// If not set, swap interval uses GPU v-sync configuration
// Framerate can be setup using SetTargetFPS()
@ -195,6 +200,8 @@ void ToggleFullscreen()
fullscreen = !fullscreen; // Toggle fullscreen flag
glfwDestroyWindow(window); // Destroy the current window (we will recreate it!)
// TODO: WARNING! All loaded resources are lost, we loose Context!
// NOTE: Window aspect ratio is always windowWidth / windowHeight
if (fullscreen) window = glfwCreateWindow(windowWidth, windowHeight, windowTitle, glfwGetPrimaryMonitor(), NULL); // Fullscreen mode
@ -498,6 +505,16 @@ Vector2 GetMousePosition()
return position;
}
// Returns mouse wheel movement Y
int GetMouseWheelMove()
{
previousMouseWheelY = currentMouseWheelY;
currentMouseWheelY = 0;
return previousMouseWheelY;
}
// Detect if a gamepad is available
bool IsGamepadAvailable(int gamepad)
{
@ -602,6 +619,12 @@ static void ErrorCallback(int error, const char *description)
//fprintf(stderr, description);
}
// GLFW3 Srolling Callback, runs on mouse wheel
static void ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
currentMouseWheelY = (int)yoffset;
}
// GLFW3 Keyboard Callback, runs on key pressed
static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
@ -662,8 +685,6 @@ static void InitGraphicsDevice()
glMatrixMode(GL_MODELVIEW); // Switch back to MODELVIEW matrix
glLoadIdentity(); // Reset current matrix (MODELVIEW)
glDisable(GL_LIGHTING); // Lighting Disabled...
// TODO: Create an efficient Lighting System with proper functions (raylib 1.x)
/*
glEnable(GL_COLOR_MATERIAL); // Enable materials, causes some glMaterial atributes to track the current color (glColor)...

+ 114
- 107
src/models.c 查看文件

@ -49,7 +49,7 @@
//----------------------------------------------------------------------------------
// Module specific Functions Declaration
//----------------------------------------------------------------------------------
o">// No private (static) functions in this module
k">static float GetHeightValue(Color pixel);
//----------------------------------------------------------------------------------
// Module Functions Definition
@ -465,100 +465,100 @@ Model LoadModel(const char *fileName)
int numTexCoords = 0;
int numTriangles = 0;
FILE* objfile;
FILE* objFile;
objfile = fopen(fileName, "rt");
objFile = fopen(fileName, "rt");
while(!feof(objfile))
while(!feof(objFile))
{
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
switch(dataType)
{
case '#': // It's a comment
{
fgets(comments, 200, objfile);
fgets(comments, 200, objFile);
} break;
case 'v':
{
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
if (dataType == 't') // Read texCoord
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
while (dataType == 'v')
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
}
if (dataType == '#')
{
fscanf(objfile, "%i", &numTexCoords);
fscanf(objFile, "%i", &numTexCoords);
}
else printf("Ouch! Something was wrong...");
fgets(comments, 200, objfile);
fgets(comments, 200, objFile);
}
else if (dataType == 'n') // Read normals
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
while (dataType == 'v')
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
}
if (dataType == '#')
{
fscanf(objfile, "%i", &numNormals);
fscanf(objFile, "%i", &numNormals);
}
else printf("Ouch! Something was wrong...");
fgets(comments, 200, objfile);
fgets(comments, 200, objFile);
}
else // Read vertex
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
while (dataType == 'v')
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
}
if (dataType == '#')
{
fscanf(objfile, "%i", &numVertex);
fscanf(objFile, "%i", &numVertex);
}
else printf("Ouch! Something was wrong...");
fgets(comments, 200, objfile);
fgets(comments, 200, objFile);
}
} break;
case 'f':
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
while (dataType == 'f')
{
fgets(comments, 200, objfile);
fscanf(objfile, "%c", &dataType);
fgets(comments, 200, objFile);
fscanf(objFile, "%c", &dataType);
}
if (dataType == '#')
{
fscanf(objfile, "%i", &numTriangles);
fscanf(objFile, "%i", &numTriangles);
}
else printf("Ouch! Something was wrong...");
fgets(comments, 200, objfile);
fgets(comments, 200, objFile);
} break;
default: break;
@ -581,51 +581,51 @@ Model LoadModel(const char *fileName)
int countMaxVertex = 0;
rewind(objfile);
rewind(objFile);
while(!feof(objfile))
while(!feof(objFile))
{
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
switch(dataType)
{
case '#':
{
fgets(comments, 200, objfile);
fgets(comments, 200, objFile);
} break;
case 'v':
{
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
if (dataType == 't') // Read texCoord
{
float useless = 0;
fscanf(objfile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
fscanf(objFile, "%f %f %f", &midTexCoords[countTexCoords].x, &midTexCoords[countTexCoords].y, &useless);
countTexCoords++;
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
}
else if (dataType == 'n') // Read normals
{
fscanf(objfile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
fscanf(objFile, "%f %f %f", &midNormals[countNormals].x, &midNormals[countNormals].y, &midNormals[countNormals].z );
countNormals++;
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
}
else // Read vertex
{
fscanf(objfile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
fscanf(objFile, "%f %f %f", &midVertices[countVertex].x, &midVertices[countVertex].y, &midVertices[countVertex].z );
countVertex++;
fscanf(objfile, "%c", &dataType);
fscanf(objFile, "%c", &dataType);
}
} break;
case 'f':
{
int vNum, vtNum, vnNum;
fscanf(objfile, "%c", &dataType);
fscanf(objfile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
fscanf(objFile, "%c", &dataType);
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
model.vertices[countMaxVertex] = midVertices[vNum-1];
model.normals[countMaxVertex] = midNormals[vnNum-1];
@ -633,7 +633,7 @@ Model LoadModel(const char *fileName)
model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
countMaxVertex++;
fscanf(objfile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
model.vertices[countMaxVertex] = midVertices[vNum-1];
model.normals[countMaxVertex] = midNormals[vnNum-1];
@ -641,7 +641,7 @@ Model LoadModel(const char *fileName)
model.texcoords[countMaxVertex].y = -midTexCoords[vtNum-1].y;
countMaxVertex++;
fscanf(objfile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
fscanf(objFile, "%i/%i/%i", &vNum, &vtNum, &vnNum);
model.vertices[countMaxVertex] = midVertices[vNum-1];
model.normals[countMaxVertex] = midNormals[vnNum-1];
@ -653,14 +653,13 @@ Model LoadModel(const char *fileName)
}
}
fclose(objfile);
fclose(objFile);
return model;
}
// Load a heightmap image as a 3d model
// TODO: Just do it...
Model LoadHeightmap(Image heightmap, Vector3 resolution)
Model LoadHeightmap(Image heightmap, float maxHeight)
{
Model model;
@ -676,17 +675,72 @@ Model LoadHeightmap(Image heightmap, Vector3 resolution)
model.vertices = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
model.normals = (Vector3 *)malloc(model.numVertices * sizeof(Vector3));
model.texcoords = (Vector2 *)malloc(model.numVertices * sizeof(Vector2));
int vCounter = 0;
int trisCounter = 0;
float scaleFactor = maxHeight/255; // TODO: Review scaleFactor calculation
for(int z = 0; z < mapZ; z++)
for(int z = 0; z < mapZo">-1; z++)
{
for(int x = 0; x < mapX; x++)
for(int x = 0; x < mapXo">-1; x++)
{
// TODO: Fill vertices array with data
// Fill vertices array with data
//----------------------------------------------------------
// one triangle - 3 vertex
model.vertices[vCounter].x = x;
model.vertices[vCounter].y = GetHeightValue(heightmap.pixels[x + z*mapX])*scaleFactor;
model.vertices[vCounter].z = z;
model.vertices[vCounter+1].x = x;
model.vertices[vCounter+1].y = GetHeightValue(heightmap.pixels[x + (z+1)*mapX])*scaleFactor;
model.vertices[vCounter+1].z = z+1;
model.vertices[vCounter+2].x = x+1;
model.vertices[vCounter+2].y = GetHeightValue(heightmap.pixels[(x+1) + z*mapX])*scaleFactor;
model.vertices[vCounter+2].z = z;
// another triangle - 3 vertex
model.vertices[vCounter+3] = model.vertices[vCounter+2];
model.vertices[vCounter+4] = model.vertices[vCounter+1];
model.vertices[vCounter+5].x = x+1;
model.vertices[vCounter+5].y = GetHeightValue(heightmap.pixels[(x+1) + (z+1)*mapX])*scaleFactor;
model.vertices[vCounter+5].z = z+1;
// Fill texcoords array with data
//--------------------------------------------------------------
model.texcoords[vCounter].x = (float)x / (mapX-1);
model.texcoords[vCounter].y = (float)z / (mapZ-1);
model.texcoords[vCounter+1].x = (float)x / (mapX-1);
model.texcoords[vCounter+1].y = (float)(z+1) / (mapZ-1);
model.texcoords[vCounter+2].x = (float)(x+1) / (mapX-1);
model.texcoords[vCounter+2].y = (float)z / (mapZ-1);
model.texcoords[vCounter+3] = model.texcoords[vCounter+2];
model.texcoords[vCounter+4] = model.texcoords[vCounter+1];
model.texcoords[vCounter+5].x = (float)(x+1) / (mapX-1);
model.texcoords[vCounter+5].y = (float)(z+1) / (mapZ-1);
// Fill normals array with data
//--------------------------------------------------------------
// TODO: Review normals calculation
model.normals[vCounter] = (Vector3){ 0.0f, 1.0f, 0.0f };
model.normals[vCounter+1] = (Vector3){ 0.0f, 1.0f, 0.0f };
model.normals[vCounter+2] = (Vector3){ 0.0f, 1.0f, 0.0f };
model.normals[vCounter+3] = (Vector3){ 0.0f, 1.0f, 0.0f };
model.normals[vCounter+4] = (Vector3){ 0.0f, 1.0f, 0.0f };
model.normals[vCounter+5] = (Vector3){ 0.0f, 1.0f, 0.0f };
vCounter += 6;
trisCounter += 2;
}
}
//SmoothHeightmap(&model); // TODO: Smooth vertex interpolation
return model;
}
@ -702,6 +756,7 @@ void UnloadModel(Model model)
void DrawModel(Model model, Vector3 position, float scale, Color color)
{
// NOTE: For models we use Vertex Arrays (OpenGL 1.1)
//static int rotation = 0;
glEnableClientState(GL_VERTEX_ARRAY); // Enable vertex array
glEnableClientState(GL_TEXTURE_COORD_ARRAY); // Enable texture coords array
@ -725,6 +780,8 @@ void DrawModel(Model model, Vector3 position, float scale, Color color)
glDisableClientState(GL_VERTEX_ARRAY); // Disable vertex array
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // Disable texture coords array
glDisableClientState(GL_NORMAL_ARRAY); // Disable normals array
//rotation += 10;
}
// Draw a textured model
@ -787,58 +844,8 @@ void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vec
glDisable(GL_TEXTURE_2D);
}
// Draw a heightmap using a provided image data
t">void DrawHeightmap(Image heightmap, Vector3 centerPos, Vector3 scale, Color color)
// Get current vertex y altitude (proportional to pixel colors in grayscale)
">static float GetHeightValue(Color pixel)
{
// NOTE: Pixel-data is interpreted as grey-scale (even being a color image)
// NOTE: Heightmap resolution will depend on image size (one quad per pixel)
// TODO: Review how this function works... probably we need:
// Model LoadHeightmap(Image heightmap, Vector3 resolution);
// NOTE: We are allocating and de-allocating vertex data every frame! --> framerate drops 80%! CRAZY!
Vector3 *terrainVertex = (Vector3 *)malloc(heightmap.width * heightmap.height * sizeof(Vector3));
for (int z = 0; z < heightmap.height; z++)
{
for (int x = 0; x < heightmap.width; x++)
{
terrainVertex[z*heightmap.height + x].x = (float)(x*scale.x);
terrainVertex[z*heightmap.height + x].y = ((float)heightmap.pixels[z*heightmap.height + x].r +
(float)heightmap.pixels[z*heightmap.height + x].g +
(float)heightmap.pixels[z*heightmap.height + x].b) / 3 * scale.y;
terrainVertex[z*heightmap.height + x].z = (float)(-z*scale.z);
}
}
// TODO: Texture coordinates and normals computing
for (int z = 0; z < heightmap.height-1; z++)
{
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < heightmap.width; x++)
{
glColor3f((float)heightmap.pixels[z*heightmap.height + x].r / 255.0f,
(float)heightmap.pixels[z*heightmap.height + x].g / 255.0f,
(float)heightmap.pixels[z*heightmap.height + x].b / 255.0f);
glVertex3f(terrainVertex[z*heightmap.height + x].x, terrainVertex[z*heightmap.height + x].y, terrainVertex[z*heightmap.height + x].z);
glVertex3f(terrainVertex[(z+1)*heightmap.height + x].x, terrainVertex[(z+1)*heightmap.height + x].y, terrainVertex[(z+1)*heightmap.height + x].z);
}
glEnd();
}
free(terrainVertex);
}
void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vector3 scale, Color tint)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture.glId);
// NOTE: No texture coordinates or normals defined at this moment...
DrawHeightmap(heightmap, centerPos, scale, tint);
glDisable(GL_TEXTURE_2D);
return (((float)pixel.r + (float)pixel.g + (float)pixel.b)/3);
}

+ 4
- 4
src/raylib.h 查看文件

@ -65,6 +65,7 @@
#define KEY_SPACE 32
#define KEY_ESCAPE 256
#define KEY_ENTER 257
#define KEY_BACKSPACE 259
#define KEY_RIGHT 262
#define KEY_LEFT 263
#define KEY_DOWN 264
@ -278,6 +279,7 @@ bool IsMouseButtonUp(int button); // Detect if a mouse but
int GetMouseX(); // Returns mouse position X
int GetMouseY(); // Returns mouse position Y
Vector2 GetMousePosition(); // Returns mouse position XY
int GetMouseWheelMove(); // Returns mouse wheel movement Y
bool IsGamepadAvailable(int gamepad); // Detect if a gamepad is available
Vector2 GetGamepadMovement(int gamepad); // Return axis movement vector for a gamepad
@ -323,7 +325,7 @@ Image LoadImage(const char *fileName);
Image LoadImageFromRES(const char *rresName, int resId); // Load an image from rRES file (raylib Resource)
Texture2D LoadTexture(const char *fileName); // Load an image as texture into GPU memory
Texture2D LoadTextureFromRES(const char *rresName, int resId); // Load an image as texture from rRES file (raylib Resource)
Texture2D CreateTexture2D(Image image); // Create a Texture2D from Image data
Texture2D CreateTexture(Image image); // Create a Texture2D from Image data
void UnloadImage(Image image); // Unload image from CPU memory (RAM)
void UnloadTexture(Texture2D texture); // Unload texture from GPU memory
@ -370,17 +372,15 @@ void DrawGizmo(Vector3 position, bool orbits);
//------------------------------------------------------------------------------------
Model LoadModel(const char *fileName); // Load a 3d model (.OBJ)
//Model LoadModelFromRES(const char *rresName, int resId); // TODO: Load a 3d model from rRES file (raylib Resource)
Model LoadHeightmap(Image heightmap, float maxHeight); // Load a heightmap image as a 3d model
void UnloadModel(Model model); // Unload 3d model from memory
void DrawModel(Model model, Vector3 position, float scale, Color color); // Draw a model
void DrawModelEx(Model model, Texture2D texture, Vector3 position, float scale, Color tint); // Draw a textured model
void DrawModelWires(Model model, Vector3 position, float scale, Color color); // Draw a model wires
// NOTE: The following functions work but are incomplete or require some revision
// DrawHeightmap is extremely inefficient and can impact performance up to 60%
void DrawBillboard(Camera camera, Texture2D texture, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x)
void DrawBillboardRec(Camera camera, Texture2D texture, Rectangle sourceRec, Vector3 basePos, float size, Color tint); // REVIEW: Draw a billboard (raylib 1.x)
void DrawHeightmap(Image heightmap, Vector3 centerPos, Vector3 scale, Color color); // REVIEW: Draw heightmap using image map (raylib 1.x)
void DrawHeightmapEx(Image heightmap, Texture2D texture, Vector3 centerPos, Vector3 scale, Color tint); // REVIEW: Draw textured heightmap (raylib 1.x)
//------------------------------------------------------------------------------------
// Audio Loading and Playing Functions (Module: audio)

+ 514
- 0
src/stb_image_write.h 查看文件

@ -0,0 +1,514 @@
/* stbiw-0.92 - public domain - http://nothings.org/stb/stb_image_write.h
writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
no warranty implied; use at your own risk
Before #including,
#define STB_IMAGE_WRITE_IMPLEMENTATION
in the file that you want to have the implementation.
ABOUT:
This header file is a library for writing images to C stdio. It could be
adapted to write to memory or a general streaming interface; let me know.
The PNG output is not optimal; it is 20-50% larger than the file
written by a decent optimizing implementation. This library is designed
for source code compactness and simplicitly, not optimal image file size
or run-time performance.
USAGE:
There are three functions, one for each image file format:
int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
Each function returns 0 on failure and non-0 on success.
The functions create an image file defined by the parameters. The image
is a rectangle of pixels stored from left-to-right, top-to-bottom.
Each pixel contains 'comp' channels of data stored interleaved with 8-bits
per channel, in the following order: 1=L, 2=LA, 3=RGB, 4=RGBA. (L is
luminance, i.e. monochrome "color", i.e. grey value.) The rectangle is
'w' pixels wide and 'h' pixels tall. The *data pointer points to the
first byte of the top-left-most pixel. For PNG, "stride_in_bytes" is
the distance in bytes from the first byte of a row of pixels to the
first byte of the next row of pixels. Other file formats assume the
first byte of the each row of pixels begins immediately after the last
byte of the previous row.
PNG creates output files with the same number of components as the input.
The BMP and TGA formats expand Y to RGB in the file format. BMP does not
output alpha.
PNG supports writing rectangles of data even when the bytes storing rows of
data are not consecutive in memory (e.g. sub-rectangles of a larger image),
by supplying the stride between the beginning of adjacent rows. The other
formats do not. (Thus you cannot write an in-memory BMP through the BMP
writer, both because it is in BGR order and because it may have padding
at the end of the line.)
*/
#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H
#ifdef __cplusplus
extern "C" {
#endif
extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
#ifdef __cplusplus
}
#endif
#endif//INCLUDE_STB_IMAGE_WRITE_H
#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
static void writefv(FILE *f, const char *fmt, va_list v)
{
while (*fmt) {
switch (*fmt++) {
case ' ': break;
case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
case '2': { int x = va_arg(v,int); unsigned char b[2];
b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
fwrite(b,2,1,f); break; }
case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
fwrite(b,4,1,f); break; }
default:
assert(0);
return;
}
}
}
static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
{
unsigned char arr[3];
arr[0] = a, arr[1] = b, arr[2] = c;
fwrite(arr, 3, 1, f);
}
static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
{
unsigned char bg[3] = { 255, 0, 255}, px[3];
stbiw_uint32 zero = 0;
int i,j,k, j_end;
if (y <= 0)
return;
if (vdir < 0)
j_end = -1, j = y-1;
else
j_end = y, j = 0;
for (; j != j_end; j += vdir) {
for (i=0; i < x; ++i) {
unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
if (write_alpha < 0)
fwrite(&d[comp-1], 1, 1, f);
switch (comp) {
case 1:
case 2: write3(f, d[0],d[0],d[0]);
break;
case 4:
if (!write_alpha) {
// composite against pink background
for (k=0; k < 3; ++k)
px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
break;
}
/* FALLTHROUGH */
case 3:
write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
break;
}
if (write_alpha > 0)
fwrite(&d[comp-1], 1, 1, f);
}
fwrite(&zero,scanline_pad,1,f);
}
}
static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
{
FILE *f;
if (y < 0 || x < 0) return 0;
f = fopen(filename, "wb");
if (f) {
va_list v;
va_start(v, fmt);
writefv(f, fmt, v);
va_end(v);
write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
fclose(f);
}
return f != NULL;
}
int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
{
int pad = (-x*3) & 3;
return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
"11 4 22 4" "4 44 22 444444",
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
}
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
{
int has_alpha = !(comp & 1);
return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
"111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha);
}
// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
#define stbi__sbraw(a) ((int *) (a) - 2)
#define stbi__sbm(a) stbi__sbraw(a)[0]
#define stbi__sbn(a) stbi__sbraw(a)[1]
#define stbi__sbneedgrow(a,n) ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a))
#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0)
#define stbi__sbgrow(a,n) stbi__sbgrowf((void **) &(a), (n), sizeof(*(a)))
#define stbi__sbpush(a, v) (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v))
#define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0)
#define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)),0 : 0)
static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
{
int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1;
void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
assert(p);
if (p) {
if (!*arr) ((int *) p)[1] = 0;
*arr = (void *) ((int *) p + 2);
stbi__sbm(*arr) = m;
}
return *arr;
}
static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
{
while (*bitcount >= 8) {
stbi__sbpush(data, (unsigned char) *bitbuffer);
*bitbuffer >>= 8;
*bitcount -= 8;
}
return data;
}
static int stbi__zlib_bitrev(int code, int codebits)
{
int res=0;
while (codebits--) {
res = (res << 1) | (code & 1);
code >>= 1;
}
return res;
}
static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
{
int i;
for (i=0; i < limit && i < 258; ++i)
if (a[i] != b[i]) break;
return i;
}
static unsigned int stbi__zhash(unsigned char *data)
{
stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
hash ^= hash << 3;
hash += hash >> 5;
hash ^= hash << 4;
hash += hash >> 17;
hash ^= hash << 25;
hash += hash >> 6;
return hash;
}
#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
#define stbi__zlib_add(code,codebits) \
(bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
#define stbi__zlib_huffa(b,c) stbi__zlib_add(stbi__zlib_bitrev(b,c),c)
// default huffman tables
#define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8)
#define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9)
#define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256,7)
#define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280,8)
#define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
#define stbi__ZHASH 16384
unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };
static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
unsigned int bitbuf=0;
int i,j, bitcount=0;
unsigned char *out = NULL;
unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack!
if (quality < 5) quality = 5;
stbi__sbpush(out, 0x78); // DEFLATE 32K window
stbi__sbpush(out, 0x5e); // FLEVEL = 1
stbi__zlib_add(1,1); // BFINAL = 1
stbi__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
for (i=0; i < stbi__ZHASH; ++i)
hash_table[i] = NULL;
i=0;
while (i < data_len-3) {
// hash next 3 bytes of data to be compressed
int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3;
unsigned char *bestloc = 0;
unsigned char **hlist = hash_table[h];
int n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32768) { // if entry lies within window
int d = stbi__zlib_countm(hlist[j], data+i, data_len-i);
if (d >= best) best=d,bestloc=hlist[j];
}
}
// when hash table entry is too long, delete half the entries
if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) {
memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
stbi__sbn(hash_table[h]) = quality;
}
stbi__sbpush(hash_table[h],data+i);
if (bestloc) {
// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
h = stbi__zhash(data+i+1)&(stbi__ZHASH-1);
hlist = hash_table[h];
n = stbi__sbcount(hlist);
for (j=0; j < n; ++j) {
if (hlist[j]-data > i-32767) {
int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1);
if (e > best) { // if next match is better, bail on current match
bestloc = NULL;
break;
}
}
}
}
if (bestloc) {
int d = data+i - bestloc; // distance back
assert(d <= 32767 && best <= 258);
for (j=0; best > lengthc[j+1]-1; ++j);
stbi__zlib_huff(j+257);
if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
for (j=0; d > distc[j+1]-1; ++j);
stbi__zlib_add(stbi__zlib_bitrev(j,5),5);
if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
i += best;
} else {
stbi__zlib_huffb(data[i]);
++i;
}
}
// write out final bytes
for (;i < data_len; ++i)
stbi__zlib_huffb(data[i]);
stbi__zlib_huff(256); // end of block
// pad with 0 bits to byte boundary
while (bitcount)
stbi__zlib_add(0,1);
for (i=0; i < stbi__ZHASH; ++i)
(void) stbi__sbfree(hash_table[i]);
{
// compute adler32 on input
unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
int j=0;
while (j < data_len) {
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
s1 %= 65521, s2 %= 65521;
j += blocklen;
blocklen = 5552;
}
stbi__sbpush(out, (unsigned char) (s2 >> 8));
stbi__sbpush(out, (unsigned char) s2);
stbi__sbpush(out, (unsigned char) (s1 >> 8));
stbi__sbpush(out, (unsigned char) s1);
}
*out_len = stbi__sbn(out);
// make returned pointer freeable
memmove(stbi__sbraw(out), out, *out_len);
return (unsigned char *) stbi__sbraw(out);
}
unsigned int stbi__crc32(unsigned char *buffer, int len)
{
static unsigned int crc_table[256];
unsigned int crc = ~0u;
int i,j;
if (crc_table[1] == 0)
for(i=0; i < 256; i++)
for (crc_table[i]=i, j=0; j < 8; ++j)
crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
for (i=0; i < len; ++i)
crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
return ~crc;
}
#define stbi__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbi__wp32(data,v) stbi__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3])
static void stbi__wpcrc(unsigned char **data, int len)
{
unsigned int crc = stbi__crc32(*data - len - 4, len+4);
stbi__wp32(*data, crc);
}
static unsigned char stbi__paeth(int a, int b, int c)
{
int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
if (pa <= pb && pa <= pc) return (unsigned char) a;
if (pb <= pc) return (unsigned char) b;
return (unsigned char) c;
}
unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
int ctype[5] = { -1, 0, 4, 2, 6 };
unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
unsigned char *out,*o, *filt, *zlib;
signed char *line_buffer;
int i,j,k,p,zlen;
if (stride_bytes == 0)
stride_bytes = x * n;
filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
for (j=0; j < y; ++j) {
static int mapping[] = { 0,1,2,3,4 };
static int firstmap[] = { 0,1,0,5,6 };
int *mymap = j ? mapping : firstmap;
int best = 0, bestval = 0x7fffffff;
for (p=0; p < 2; ++p) {
for (k= p?best:0; k < 5; ++k) {
int type = mymap[k],est=0;
unsigned char *z = pixels + stride_bytes*j;
for (i=0; i < n; ++i)
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
case 4: line_buffer[i] = (signed char) (z[i] - stbi__paeth(0,z[i-stride_bytes],0)); break;
case 5: line_buffer[i] = z[i]; break;
case 6: line_buffer[i] = z[i]; break;
}
for (i=n; i < x*n; ++i) {
switch (type) {
case 0: line_buffer[i] = z[i]; break;
case 1: line_buffer[i] = z[i] - z[i-n]; break;
case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break;
}
}
if (p) break;
for (i=0; i < x*n; ++i)
est += abs((signed char) line_buffer[i]);
if (est < bestval) { bestval = est; best = k; }
}
}
// when we get here, best contains the filter type, and line_buffer contains the data
filt[j*(x*n+1)] = (unsigned char) best;
memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
}
free(line_buffer);
zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
free(filt);
if (!zlib) return 0;
// each tag requires 12 bytes of overhead
out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
if (!out) return 0;
*out_len = 8 + 12+13 + 12+zlen + 12;
o=out;
memcpy(o,sig,8); o+= 8;
stbi__wp32(o, 13); // header length
stbi__wptag(o, "IHDR");
stbi__wp32(o, x);
stbi__wp32(o, y);
*o++ = 8;
*o++ = (unsigned char) ctype[n];
*o++ = 0;
*o++ = 0;
*o++ = 0;
stbi__wpcrc(&o,13);
stbi__wp32(o, zlen);
stbi__wptag(o, "IDAT");
memcpy(o, zlib, zlen); o += zlen; free(zlib);
stbi__wpcrc(&o, zlen);
stbi__wp32(o,0);
stbi__wptag(o, "IEND");
stbi__wpcrc(&o,0);
assert(o == out + *out_len);
return out;
}
int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
{
FILE *f;
int len;
unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
if (!png) return 0;
f = fopen(filename, "wb");
if (!f) { free(png); return 0; }
fwrite(png, 1, len, f);
fclose(f);
free(png);
return 1;
}
#endif // STB_IMAGE_WRITE_IMPLEMENTATION
/* Revision history
0.92 (2010-08-01)
casts to unsigned char to fix warnings
0.91 (2010-07-17)
first public release
0.90 first internal release
*/

+ 1
- 1
src/text.c 查看文件

@ -611,7 +611,7 @@ static SpriteFont LoadRBMF(const char *fileName)
printf("Image reconstructed correctly... now converting it to texture...");
spriteFont.texture = CreateTexture2D(image);
spriteFont.texture = CreateTexture(image);
UnloadImage(image); // Unload image data

+ 2
- 2
src/textures.c 查看文件

@ -259,7 +259,7 @@ Texture2D LoadTextureFromRES(const char *rresName, int resId)
Texture2D texture;
Image image = LoadImageFromRES(rresName, resId);
texture = CreateTexture2D(image);
texture = CreateTexture(image);
return texture;
}
@ -283,7 +283,7 @@ Texture2D LoadTextureEx(const char *fileName, bool createPOT, bool mipmaps)
// Create a Texture2D from Image data
// NOTE: Image is not unloaded, it should be done manually...
Texture2D CreateTexture2D(Image image)
Texture2D CreateTexture(Image image)
{
Texture2D texture;

二進制
tools/rrem.exe 查看文件


Loading…
取消
儲存