Primary (DirectX 8 / .dds): Used for compressed textures to save VRAM and improve loading speeds.
Secondary (SOIL2): Handles standard formats like .png and .tga. It also acts as a fallback if a .dds file fails to load (e.g., due to unsupported pixel dimensions or header corruption).
Alternative (stb_image): While stb_image is excellent for portability, it lacks native .dds support, making it less "hybrid-friendly" for this specific DX8 workflow compared to SOIL2.
gemini AI
GraphicImageTexture.cpp
#include "StdAfx.h"
#include "../eterBase/MappedFile.h"
#include "../eterPack/EterPackManager.h"
#include "GrpImageTexture.h"
#include "SOIL2.h"
#pragma comment(lib, "soil2.lib")
#pragma comment(lib, "legacy_stdio_definitions.lib")
#pragma comment(lib, "Opengl32.lib")bool CGraphicImageTexture::CreateFromMemoryFile(UINT bufSize, const void* c_pvBuf, D3DFORMAT d3dFmt, DWORD dwFilter)
{
assert(ms_lpd3dDevice != NULL);
assert(m_lpd3dTexture == NULL);
bool bDDSLoaded = false;
static CDXTCImage image;
// 1. Önce DDS olarak dene
if (image.LoadHeaderFromMemory((const BYTE*)c_pvBuf))
{
// Header yüklendi, şimdi dokuyu oluşturmayı dene
if (CreateDDSTexture(image, (const BYTE*)c_pvBuf))
{
bDDSLoaded = true;
}
else
{
// DDS oluşturma başarısız olduysa buraya düşer, SOIL2 deneyecek
TraceError("CGraphicImageTexture::CreateFromMemoryFile: DDS CreateDDSTexture failed, trying SOIL2 fallback.");
}
}
// 2. Eğer DDS yüklenemediyse veya hata verdiyse SOIL2 kullan
if (!bDDSLoaded)
{
int width, height, channels;
unsigned char* imgData = SOIL_load_image_from_memory(
(const unsigned char*)c_pvBuf,
bufSize,
&width,
&height,
&channels,
SOIL_LOAD_RGBA
);
if (!imgData)
{
TraceError("SOIL2 yukleme hatasi (DDS Fallback dahil): %s", SOIL_last_result());
return false;
}
// D3D8 Texture oluştur
if (FAILED(ms_lpd3dDevice->CreateTexture(width, height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, &m_lpd3dTexture)))
{
SOIL_free_image_data(imgData);
return false;
}
D3DLOCKED_RECT lockedRect;
if (SUCCEEDED(m_lpd3dTexture->LockRect(0, &lockedRect, NULL, 0)))
{
unsigned char* pDst = (unsigned char*)lockedRect.pBits;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
int i = (y * width + x) * 4;
// Pitch hesabı: D3D yüzey genişliği her zaman 4'ün katı olmayabilir,
// bu yüzden byte bazlı pitch (lockedRect.Pitch) kullanıyoruz.
int di = (y * lockedRect.Pitch) + (x * 4);
pDst[di + 0] = imgData[i + 2]; // Blue
pDst[di + 1] = imgData[i + 1]; // Green
pDst[di + 2] = imgData[i + 0]; // Red
pDst[di + 3] = imgData[i + 3]; // Alpha
}
}
m_lpd3dTexture->UnlockRect(0);
}
m_width = width;
m_height = height;
SOIL_free_image_data(imgData);
}
m_bEmpty = false;
return true;
}#include "SOIL2.h"
bool CGuildMarkUploader::__Load(const char* c_szFileName, UINT* peError)
{
int width = 0;
int height = 0;
int channels = 0;
// SOIL2 ile resmi RGBA olarak yükle
unsigned char* imgData = SOIL_load_image(c_szFileName, &width, &height, &channels, SOIL_LOAD_RGBA);
if (!imgData)
{
*peError = ERROR_LOAD;
return false;
}
// Genişlik kontrolü
if (width != SGuildMark::WIDTH)
{
SOIL_free_image_data(imgData);
*peError = ERROR_WIDTH;
return false;
}
// Yükseklik kontrolü
if (height != SGuildMark::HEIGHT)
{
SOIL_free_image_data(imgData);
*peError = ERROR_HEIGHT;
return false;
}
// SOIL2 veriyi RGBA verir, Metin2 lonca simgesi için BGRA formatı gerekir.
// Pikselleri m_kMark.m_apxBuf içine kopyalarken renk kanallarını çeviriyoruz.
unsigned char* pDst = (unsigned char*)m_kMark.m_apxBuf;
for (int i = 0; i < width * height; ++i)
{
int srcIdx = i * 4;
int dstIdx = i * 4;
pDst[dstIdx + 0] = imgData[srcIdx + 2]; // Blue
pDst[dstIdx + 1] = imgData[srcIdx + 1]; // Green
pDst[dstIdx + 2] = imgData[srcIdx + 0]; // Red
pDst[dstIdx + 3] = imgData[srcIdx + 3]; // Alpha
}
// Belleği temizle
SOIL_free_image_data(imgData);
return true;
}pythonappilciionmodule
#include "SOIL2.h"
// #include <SOIL2.h>
PyObject* appGetImageInfo(PyObject* poSelf, PyObject* poArgs)
{
char* szFileName;
if (!PyTuple_GetString(poArgs, 0, &szFileName))
return Py_BuildException();
int width = 0;
int height = 0;
int channels = 0;
BOOL canLoad = FALSE;
// SOIL_load_image doğrudan resmi yüklemeye çalışır.
// Eğer dosya yoksa veya formatı desteklemiyorsa NULL döner.
unsigned char* temp_info = SOIL_load_image(szFileName, &width, &height, &channels, SOIL_LOAD_AUTO);
if (temp_info)
{
canLoad = TRUE;
// Boyutları aldık, belleği hemen temizle
SOIL_free_image_data(temp_info);
}
else
{
// Dosya bulunamadı veya SOIL2 okuyamadı
canLoad = FALSE;
width = 0;
height = 0;
}
return Py_BuildValue("iii", canLoad, width, height);
}Project Specifications
Platform: Windows 32-bit (x86)
Compiler: Visual Studio 2022
Language Standard: ISO C++20 Standard (/std:c++20)
Runtime Library: Multi-threaded (/MT) — Static linking
lib konuya ekliyorum.
cmake ile build alabilirsiniz.
cmke v3 latest
#include "image_array.h"
#include <stdlib.h>
#include <string.h>
#include "image_helper.h"
extern const char *result_string_pointer;
void SOIL_image_array_free(SOIL_ImageArray *imgArray){
if(imgArray == NULL){
return;
}
if(imgArray->data != NULL){
for(int i = 0; i < imgArray->layers; i++){
if(imgArray->data[i] != NULL){
free(imgArray->data[i]);
}
}
free(imgArray->data);
}
imgArray->data = NULL;
imgArray->width = 0;
imgArray->height = 0;
imgArray->layers = 0;
imgArray->channels = 0;
}
void image_array_invert_y(SOIL_ImageArray* imgArray){
if (!imgArray || !imgArray->data)
return;
const size_t rowBytes = (size_t)(imgArray->width) * (size_t)(imgArray->channels);
for (int layer = 0; layer < imgArray->layers; ++layer) {
unsigned char *image = imgArray->data[layer];
if (!image) continue;
for (int y = 0; y < imgArray->height / 2; ++y) {
unsigned char *rowTop = image + (size_t)y * rowBytes;
unsigned char *rowBottom = image + (size_t)(imgArray->height - 1 - y) * rowBytes;
for (size_t x = 0; x < rowBytes; ++x) {
unsigned char temp = rowTop[x];
rowTop[x] = rowBottom[x];
rowBottom[x] = temp;
}
}
}
}
void image_array_premultiply_alpha(SOIL_ImageArray* imgArray){
if (!imgArray || !imgArray->data)
return;
const size_t numPixels = (size_t)(imgArray->width) * (size_t)(imgArray->height);
for (int layer = 0; layer < imgArray->layers; ++layer) {
unsigned char *image = imgArray->data[layer];
if (!image) continue;
for (size_t i = 0; i < numPixels; ++i) {
unsigned char *pixel = image + i * (size_t)(imgArray->channels);
if (imgArray->channels >= 4) {
float alpha = pixel[3] / 255.0f;
pixel[0] = (unsigned char)(pixel[0] * alpha);
pixel[1] = (unsigned char)(pixel[1] * alpha);
pixel[2] = (unsigned char)(pixel[2] * alpha);
}
}
}
}
void image_array_to_NTSC_safe(SOIL_ImageArray* imgArray){
if (!imgArray || !imgArray->data)
return;
const size_t numPixels = (size_t)(imgArray->width) * (size_t)(imgArray->height);
for (int layer = 0; layer < imgArray->layers; ++layer) {
unsigned char *image = imgArray->data[layer];
if (!image) continue;
for (size_t i = 0; i < numPixels; ++i) {
unsigned char *pixel = image + i * (size_t)(imgArray->channels);
if (imgArray->channels >= 3) {
unsigned char r = pixel[0];
unsigned char g = pixel[1];
unsigned char b = pixel[2];
unsigned char y = (unsigned char)(0.299f * r + 0.587f * g + 0.114f * b);
unsigned char co = (unsigned char)(r - b + 128);
unsigned char cg = (unsigned char)(-0.168736f * r - 0.331264f * g + 0.5f * b + 128);
pixel[0] = co;
pixel[1] = cg;
pixel[2] = y;
}
}
}
}
void image_array_to_YCoCg(SOIL_ImageArray* imgArray){
if (!imgArray || !imgArray->data)
return;
const size_t numPixels = (size_t)(imgArray->width) * (size_t)(imgArray->height);
for (int layer = 0; layer < imgArray->layers; ++layer) {
unsigned char *image = imgArray->data[layer];
if (!image) continue;
for (size_t i = 0; i < numPixels; ++i) {
unsigned char *pixel = image + i * (size_t)(imgArray->channels);
if (imgArray->channels >= 3) {
unsigned char r = pixel[0];
unsigned char g = pixel[1];
unsigned char b = pixel[2];
int y = ( r + ( 2 * g ) + b ) >> 2;
int co = ( r - b ) >> 1;
int cg = ( -r + ( 2 * g ) - b ) >> 2;
pixel[0] = (unsigned char)(co + 128);
pixel[1] = (unsigned char)(cg + 128);
pixel[2] = (unsigned char)(y);
}
}
}
}
static int next_power_of_two(int v)
{
int r = 1;
while (r < v)
r <<= 1;
return r;
}
int image_array_resize_POT(SOIL_ImageArray *imgArray)
{
if (!imgArray || !imgArray->data)
return 1;
int new_w = next_power_of_two(imgArray->width);
int new_h = next_power_of_two(imgArray->height);
if (new_w == imgArray->width && new_h == imgArray->height)
return 1;
for (int layer = 0; layer < imgArray->layers; ++layer) {
unsigned char *src = imgArray->data[layer];
if (!src)
continue;
unsigned char *dst = (unsigned char*)malloc(
(size_t)new_w * (size_t)new_h * (size_t)imgArray->channels
);
if (!dst)
return 0;
up_scale_image(
src,
imgArray->width,
imgArray->height,
imgArray->channels,
dst,
new_w,
new_h
);
free(src);
imgArray->data[layer] = dst;
}
imgArray->width = new_w;
imgArray->height = new_h;
return 1;
}
int image_array_reduce_to_max(SOIL_ImageArray *imgArray, int max_size)
{
if (!imgArray || !imgArray->data)
return 1;
if (imgArray->width <= max_size &&
imgArray->height <= max_size)
return 1;
int reduce_block_x = 1;
int reduce_block_y = 1;
if (imgArray->width > max_size)
reduce_block_x = imgArray->width / max_size;
if (imgArray->height > max_size)
reduce_block_y = imgArray->height / max_size;
int new_w = imgArray->width / reduce_block_x;
int new_h = imgArray->height / reduce_block_y;
for (int layer = 0; layer < imgArray->layers; ++layer) {
unsigned char *src = imgArray->data[layer];
if (!src)
continue;
unsigned char *dst = (unsigned char*)malloc(
(size_t)new_w * (size_t)new_h * (size_t)imgArray->channels
);
if (!dst)
return 0;
mipmap_image(
src,
imgArray->width,
imgArray->height,
imgArray->channels,
dst,
reduce_block_x,
reduce_block_y
);
free(src);
imgArray->data[layer] = dst;
}
imgArray->width = new_w;
imgArray->height = new_h;
return 1;
}
SOIL_ImageArray extract_image_array_from_atlas_grid(
const unsigned char *atlasData,
int atlasW,
int atlasH,
int cols,
int rows,
int channels
){
SOIL_ImageArray result = {0};
if (!atlasData || cols <= 0 || rows <= 0 || channels <= 0)
return result;
if (atlasW % cols != 0 || atlasH % rows != 0)
{
result_string_pointer = "Atlas cannot be evenly divided by grid";
return result;
}
int tile_w = atlasW / cols;
int tile_h = atlasH / rows;
int numLayers = cols * rows;
result.width = tile_w;
result.height = tile_h;
result.layers = numLayers;
result.channels = channels;
result.data = (unsigned char**)malloc(sizeof(unsigned char*) * numLayers);
if (!result.data){
SOIL_ImageArray empty;
memset(&empty, 0, sizeof(empty));
return empty;
}
for (int i = 0; i < numLayers; ++i)
result.data[i] = NULL;
const size_t bytesPerPixel = (size_t)channels;
const size_t tileRowBytes = (size_t)tile_w * bytesPerPixel;
const size_t atlasRowBytes = (size_t)atlasW * bytesPerPixel;
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < cols; ++c) {
int layer = r * cols + c;
unsigned char *tile =
(unsigned char*)malloc((size_t)tile_w * tile_h * bytesPerPixel);
if (!tile) {
/* cleanup */
for (int i = 0; i < numLayers; ++i)
free(result.data[i]);
free(result.data);
SOIL_ImageArray empty;
memset(&empty, 0, sizeof(empty));
return empty;
}
for (int y = 0; y < tile_h; ++y) {
const unsigned char *src =
atlasData +
((size_t)(r * tile_h + y) * atlasRowBytes) +
((size_t)c * tileRowBytes);
unsigned char *dst = tile + (size_t)y * tileRowBytes;
memcpy(dst, src, tileRowBytes);
}
result.data[layer] = tile;
}
}
return result;
}
https://virusscan.jotti.org/en-US/filescanjob/4syfytu8os
1767472146467.png
