2003-04-26 16:02:26 +00:00
|
|
|
/* util.c
|
|
|
|
*
|
|
|
|
* various string, file, list operations.
|
|
|
|
*
|
|
|
|
*
|
2002-10-12 11:37:38 +00:00
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version. The Blender
|
|
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
|
|
* about this.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL/BL DUAL LICENSE BLOCK *****
|
2003-04-26 16:02:26 +00:00
|
|
|
*
|
2002-10-12 11:37:38 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2007-03-19 19:34:04 +00:00
|
|
|
#include <stdarg.h>
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "DNA_listBase.h"
|
|
|
|
#include "BLI_storage.h"
|
|
|
|
#include "BLI_storage_types.h"
|
2006-08-20 15:22:56 +00:00
|
|
|
#include "BLI_dynamiclist.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
#include "BLI_util.h"
|
2007-02-22 10:20:27 +00:00
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2002-11-25 12:02:15 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#else
|
|
|
|
#include <io.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include "BLI_winstuff.h"
|
2007-03-19 19:34:04 +00:00
|
|
|
|
|
|
|
/* for duplicate_defgroup */
|
|
|
|
#if !(defined vsnprintf)
|
|
|
|
#define vsnprintf _vsnprintf
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef WIN32
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
2003-05-12 14:59:08 +00:00
|
|
|
#ifdef __APPLE__
|
2003-05-12 17:13:12 +00:00
|
|
|
#include <sys/param.h>
|
2003-05-12 14:59:08 +00:00
|
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
/* local */
|
|
|
|
|
|
|
|
static int add_win32_extension(char *name);
|
|
|
|
|
|
|
|
/* implementation */
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
/* Ripped this from blender.c */
|
2002-10-12 11:37:38 +00:00
|
|
|
void addlisttolist(ListBase *list1, ListBase *list2)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
if (list2->first==0) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (list1->first==0) {
|
2002-10-12 11:37:38 +00:00
|
|
|
list1->first= list2->first;
|
|
|
|
list1->last= list2->last;
|
|
|
|
}
|
|
|
|
else {
|
2007-10-04 10:50:15 +00:00
|
|
|
((Link *)list1->last)->next= list2->first;
|
|
|
|
((Link *)list2->first)->prev= list1->last;
|
2002-10-12 11:37:38 +00:00
|
|
|
list1->last= list2->last;
|
|
|
|
}
|
|
|
|
list2->first= list2->last= 0;
|
|
|
|
}
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
int BLI_stringdec(char *string, char *kop, char *start, unsigned short *numlen)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
unsigned short len, len2, nums = 0, nume = 0;
|
|
|
|
short i, found = 0;
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
len2 = len = strlen(string);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
if (len > 6) {
|
2005-04-02 15:36:57 +00:00
|
|
|
if (BLI_strncasecmp(string + len - 6, ".blend", 6) == 0) len -= 6;
|
|
|
|
else if (BLI_strncasecmp(string + len - 6, ".trace", 6) == 0) len -= 6;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
Patch provided by Shaul Kedem: Compressed files are back!
He even made a nice doc in wiki:
http://wiki.blender.org/bin/view.pl/Blenderdev/Blendgz
Usage: set the option "Compress File" in the main "File" pulldown menu.
This setting is a user-def, meaning it is not changed on reading files.
If you want it default, save it with CTRL+U.
The longest debate went over the file naming convention. Shaul started
with .blend.gz files, which gave issues in Blender because of the code
hanging out everywhere that detects blender files, and that appends the
.blend extension if needed.
Daniel Dunbar proposed to just save it as .blend, and not bother users
with such details. This is indeed the most elegant solution, with as
only drawback that old Blender executables cannot read it.
This drawback isn't very relevant at the moment, since we're heading
towards a release that isn't upward compatible anyway... the recode
going on on Meshes, Modfiers, Armatures, Poses, Actions, NLA already
have upward compatibility issues.
We might check - during the next month(s) - on a builtin system to
warn users in the future when we change things that make a file risky
to read in an older release.
2005-07-27 19:46:06 +00:00
|
|
|
if (len > 9) {
|
|
|
|
if (BLI_strncasecmp(string + len - 9, ".blend.gz", 9) == 0) len -= 9;
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if (len == len2) {
|
|
|
|
if (len > 4) {
|
2003-04-26 16:02:26 +00:00
|
|
|
/* handle .jf0 en .jf1 for jstreams */
|
2005-04-02 15:36:57 +00:00
|
|
|
if (BLI_strncasecmp(string + len - 4, ".jf", 3) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".tga", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".jpg", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".png", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".txt", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".cyc", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".enh", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".rgb", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".psx", 4) == 0) len -= 4;
|
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".ble", 4) == 0) len -= 4;
|
Orange branch: OpenEXR finally in Blender!
Credits go to Gernot Ziegler, who originally coded EXR support, and to
Austin Benesh for bringing it further. Kent Mein provided a lot of code
for integrating float buffers in Blender imbuf and ImBuf API cleanup,
and provided Make and Scons and static linking.
At this moment; the EXR libraries are a *dependency*, so you cannot get
the Orange branch compiled without having OpenEXR installed. Get the
(precompiled or sources) stuff from www.openexr.com. Current default is
that the headers and lib resides in /user/local/
Several changes/additions/fixes were added:
- EXR code only supported 'half' format (16 bits per channel). I've added
float writing, but for reading it I need tomorrow. :)
- Quite some clumsy copying of data happened in EXR code.
- cleaned up the api calls already a bit, preparing for more advanced
support
- Zbuffers were saved 16 bits, now 32 bits
- automatic adding of .exr extensions went wrong
Imbuf:
- added proper imbuf->flags and imbuf->mall support for float buffers, it
was created for *each* imbuf. :)
- found bugs for float buffers in scaling and flipping. Code there will
need more checks still
- imbuf also needs to be verified to behave properly when no 32 bits
rect exists (for saving for example)
TODO:
- support internal float images for textures, backbuf, AO probes, and
display in Image window
Hope this commit won't screwup syncing with bf-blender... :/
2006-01-09 00:40:35 +00:00
|
|
|
else if (BLI_strncasecmp(string + len - 4, ".exr", 4) == 0) len -= 4;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
for (i = len - 1; i >= 0; i--) {
|
2002-10-12 11:37:38 +00:00
|
|
|
if (string[i] == '/') break;
|
|
|
|
if (isdigit(string[i])) {
|
|
|
|
if (found){
|
|
|
|
nums = i;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
nume = i;
|
|
|
|
nums = i;
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
else {
|
2002-10-12 11:37:38 +00:00
|
|
|
if (found) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found){
|
2007-10-04 10:50:15 +00:00
|
|
|
if (start) strcpy(start,&string[nume+1]);
|
2002-10-12 11:37:38 +00:00
|
|
|
if (kop) {
|
|
|
|
strcpy(kop,string);
|
|
|
|
kop[nums]=0;
|
|
|
|
}
|
|
|
|
if (numlen) *numlen = nume-nums+1;
|
|
|
|
return ((int)atoi(&(string[nums])));
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
if (start) strcpy(start, string + len);
|
2002-10-12 11:37:38 +00:00
|
|
|
if (kop) {
|
|
|
|
strncpy(kop, string, len);
|
|
|
|
kop[len] = 0;
|
|
|
|
}
|
|
|
|
if (numlen) *numlen=0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
void BLI_stringenc(char *string, char *kop, char *start, unsigned short numlen, int pic)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
char numstr[10]="";
|
|
|
|
unsigned short len,i;
|
|
|
|
|
|
|
|
strcpy(string,kop);
|
|
|
|
|
|
|
|
if (pic>0 || numlen==4) {
|
|
|
|
len= sprintf(numstr,"%d",pic);
|
2007-10-04 10:50:15 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
for(i=len;i<numlen;i++){
|
|
|
|
strcat(string,"0");
|
|
|
|
}
|
|
|
|
strcat(string,numstr);
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
strcat(string, start);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
void BLI_newname(char *name, int add)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
char head[128], tail[128];
|
|
|
|
int pic;
|
|
|
|
unsigned short digits;
|
|
|
|
|
|
|
|
pic = BLI_stringdec(name, head, tail, &digits);
|
|
|
|
|
2003-04-26 16:02:26 +00:00
|
|
|
/* are we going from 100 -> 99 or from 10 -> 9 */
|
2002-10-12 11:37:38 +00:00
|
|
|
if (add < 0 && digits < 4 && digits > 0) {
|
|
|
|
int i, exp;
|
|
|
|
exp = 1;
|
|
|
|
for (i = digits; i > 1; i--) exp *= 10;
|
|
|
|
if (pic >= exp && (pic + add) < exp) digits--;
|
|
|
|
}
|
|
|
|
|
|
|
|
pic += add;
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (digits==4 && pic<0) pic= 0;
|
2002-10-12 11:37:38 +00:00
|
|
|
BLI_stringenc(name, head, tail, digits, pic);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BLI_addhead(ListBase *listbase, void *vlink)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link= vlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (link == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
link->next = listbase->first;
|
2007-10-04 10:50:15 +00:00
|
|
|
link->prev = NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (listbase->first) ((Link *)listbase->first)->prev = link;
|
|
|
|
if (listbase->last == NULL) listbase->last = link;
|
2002-10-12 11:37:38 +00:00
|
|
|
listbase->first = link;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BLI_addtail(ListBase *listbase, void *vlink)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link= vlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (link == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
link->next = NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
link->prev = listbase->last;
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (listbase->last) ((Link *)listbase->last)->next = link;
|
2002-10-12 11:37:38 +00:00
|
|
|
if (listbase->first == 0) listbase->first = link;
|
|
|
|
listbase->last = link;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BLI_remlink(ListBase *listbase, void *vlink)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link= vlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (link == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
if (link->next) link->next->prev = link->prev;
|
|
|
|
if (link->prev) link->prev->next = link->next;
|
|
|
|
|
|
|
|
if (listbase->last == link) listbase->last = link->prev;
|
|
|
|
if (listbase->first == link) listbase->first = link->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BLI_freelinkN(ListBase *listbase, void *vlink)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link= vlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (link == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
BLI_remlink(listbase,link);
|
|
|
|
MEM_freeN(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BLI_insertlink(ListBase *listbase, void *vprevlink, void *vnewlink)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *prevlink= vprevlink;
|
|
|
|
Link *newlink= vnewlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-04-26 16:02:26 +00:00
|
|
|
/* newlink comes after prevlink */
|
2007-10-04 10:50:15 +00:00
|
|
|
if (newlink == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
|
|
|
|
|
|
|
/* empty list */
|
|
|
|
if (listbase->first == NULL) {
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
listbase->first= newlink;
|
|
|
|
listbase->last= newlink;
|
|
|
|
return;
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
|
|
|
|
/* insert before first element */
|
|
|
|
if (prevlink == NULL) {
|
2002-10-12 11:37:38 +00:00
|
|
|
newlink->next= listbase->first;
|
|
|
|
newlink->prev= 0;
|
|
|
|
newlink->next->prev= newlink;
|
|
|
|
listbase->first= newlink;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
/* at end of list */
|
|
|
|
if (listbase->last== prevlink)
|
2002-10-12 11:37:38 +00:00
|
|
|
listbase->last = newlink;
|
|
|
|
|
|
|
|
newlink->next= prevlink->next;
|
|
|
|
prevlink->next= newlink;
|
2007-10-04 10:50:15 +00:00
|
|
|
if (newlink->next) newlink->next->prev= newlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
newlink->prev= prevlink;
|
|
|
|
}
|
|
|
|
|
2007-11-01 21:44:41 +00:00
|
|
|
/* This uses insertion sort, so NOT ok for large list */
|
|
|
|
void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
|
|
|
|
{
|
|
|
|
Link *current = NULL;
|
|
|
|
Link *previous = NULL;
|
|
|
|
Link *next = NULL;
|
|
|
|
|
|
|
|
if (cmp == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
|
|
|
|
|
|
|
if (listbase->first != listbase->last)
|
|
|
|
{
|
2007-12-10 21:04:48 +00:00
|
|
|
for( previous = listbase->first, current = previous->next; current; current = next )
|
2007-11-01 21:44:41 +00:00
|
|
|
{
|
|
|
|
next = current->next;
|
2007-12-10 21:04:48 +00:00
|
|
|
previous = current->prev;
|
2007-11-01 21:44:41 +00:00
|
|
|
|
|
|
|
BLI_remlink(listbase, current);
|
|
|
|
|
|
|
|
while(previous && cmp(previous, current) == 1)
|
|
|
|
{
|
|
|
|
previous = previous->prev;
|
|
|
|
}
|
|
|
|
|
2007-12-10 21:04:48 +00:00
|
|
|
BLI_insertlinkafter(listbase, previous, current);
|
2007-11-01 21:44:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_insertlinkafter(ListBase *listbase, void *vprevlink, void *vnewlink)
|
|
|
|
{
|
|
|
|
Link *prevlink= vprevlink;
|
|
|
|
Link *newlink= vnewlink;
|
|
|
|
|
|
|
|
/* newlink before nextlink */
|
|
|
|
if (newlink == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
|
|
|
|
|
|
|
/* empty list */
|
|
|
|
if (listbase->first == NULL) {
|
|
|
|
listbase->first= newlink;
|
|
|
|
listbase->last= newlink;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* insert at head of list */
|
|
|
|
if (prevlink == NULL) {
|
|
|
|
newlink->prev = NULL;
|
|
|
|
newlink->next = listbase->first;
|
|
|
|
((Link *)listbase->first)->prev = newlink;
|
|
|
|
listbase->first = newlink;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* at end of list */
|
|
|
|
if (listbase->last == prevlink)
|
|
|
|
listbase->last = newlink;
|
|
|
|
|
|
|
|
newlink->next = prevlink->next;
|
|
|
|
newlink->prev = prevlink;
|
|
|
|
prevlink->next = newlink;
|
|
|
|
if (newlink->next) newlink->next->prev = newlink;
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
void BLI_insertlinkbefore(ListBase *listbase, void *vnextlink, void *vnewlink)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *nextlink= vnextlink;
|
|
|
|
Link *newlink= vnewlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2003-04-26 16:02:26 +00:00
|
|
|
/* newlink before nextlink */
|
2007-10-04 10:50:15 +00:00
|
|
|
if (newlink == NULL) return;
|
|
|
|
if (listbase == NULL) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
/* empty list */
|
|
|
|
if (listbase->first == NULL) {
|
2002-10-12 11:37:38 +00:00
|
|
|
listbase->first= newlink;
|
|
|
|
listbase->last= newlink;
|
|
|
|
return;
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
|
|
|
|
/* insert at end of list */
|
|
|
|
if (nextlink == NULL) {
|
2002-10-12 11:37:38 +00:00
|
|
|
newlink->prev= listbase->last;
|
|
|
|
newlink->next= 0;
|
2007-10-04 10:50:15 +00:00
|
|
|
((Link *)listbase->last)->next= newlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
listbase->last= newlink;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
/* at beginning of list */
|
|
|
|
if (listbase->first== nextlink)
|
2002-10-12 11:37:38 +00:00
|
|
|
listbase->first = newlink;
|
|
|
|
|
|
|
|
newlink->next= nextlink;
|
|
|
|
newlink->prev= nextlink->prev;
|
|
|
|
nextlink->prev= newlink;
|
2007-10-04 10:50:15 +00:00
|
|
|
if (newlink->prev) newlink->prev->next= newlink;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void BLI_freelist(ListBase *listbase)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link, *next;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (listbase == NULL)
|
|
|
|
return;
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
link= listbase->first;
|
2007-10-04 10:50:15 +00:00
|
|
|
while (link) {
|
2002-10-12 11:37:38 +00:00
|
|
|
next= link->next;
|
|
|
|
free(link);
|
|
|
|
link= next;
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
|
|
|
|
listbase->first= NULL;
|
|
|
|
listbase->last= NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_freelistN(ListBase *listbase)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link, *next;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (listbase == NULL) return;
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
link= listbase->first;
|
2007-10-04 10:50:15 +00:00
|
|
|
while (link) {
|
2002-10-12 11:37:38 +00:00
|
|
|
next= link->next;
|
|
|
|
MEM_freeN(link);
|
|
|
|
link= next;
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
|
|
|
|
listbase->first= NULL;
|
|
|
|
listbase->last= NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int BLI_countlist(ListBase *listbase)
|
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link;
|
2002-10-12 11:37:38 +00:00
|
|
|
int count = 0;
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
if (listbase) {
|
2002-10-12 11:37:38 +00:00
|
|
|
link = listbase->first;
|
2007-10-04 10:50:15 +00:00
|
|
|
while (link) {
|
2002-10-12 11:37:38 +00:00
|
|
|
count++;
|
|
|
|
link= link->next;
|
|
|
|
}
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
return count;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
void *BLI_findlink(ListBase *listbase, int number)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2007-10-04 10:50:15 +00:00
|
|
|
Link *link = NULL;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
if (number >= 0) {
|
|
|
|
link = listbase->first;
|
|
|
|
while (link != NULL && number != 0) {
|
|
|
|
number--;
|
|
|
|
link = link->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-04 10:50:15 +00:00
|
|
|
return link;
|
|
|
|
}
|
|
|
|
|
|
|
|
int BLI_findindex(ListBase *listbase, void *vlink)
|
|
|
|
{
|
|
|
|
Link *link= NULL;
|
|
|
|
int number= 0;
|
|
|
|
|
|
|
|
if (listbase == NULL) return -1;
|
|
|
|
if (vlink == NULL) return -1;
|
|
|
|
|
|
|
|
link= listbase->first;
|
|
|
|
while (link) {
|
|
|
|
if (link == vlink)
|
|
|
|
return number;
|
|
|
|
|
|
|
|
number++;
|
|
|
|
link= link->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2006-08-20 15:22:56 +00:00
|
|
|
/*=====================================================================================*/
|
|
|
|
/* Methods for access array (realloc) */
|
|
|
|
/*=====================================================================================*/
|
|
|
|
|
|
|
|
/* remove item with index */
|
|
|
|
static void rem_array_item(struct DynamicArray *da, unsigned int index)
|
|
|
|
{
|
|
|
|
da->items[index]=NULL;
|
|
|
|
da->count--;
|
|
|
|
if(index==da->last_item_index){
|
|
|
|
while((!da->items[da->last_item_index]) && (da->last_item_index>0)){
|
|
|
|
da->last_item_index--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add array (if needed, then realloc) */
|
|
|
|
static void add_array_item(struct DynamicArray *da, void *item, unsigned int index)
|
|
|
|
{
|
|
|
|
/* realloc of access array */
|
|
|
|
if(da->max_item_index < index){
|
|
|
|
unsigned int i, max = da->max_item_index;
|
|
|
|
void **nitems;
|
|
|
|
|
|
|
|
do {
|
|
|
|
da->max_item_index += PAGE_SIZE; /* OS can allocate only PAGE_SIZE Bytes */
|
|
|
|
} while(da->max_item_index<=index);
|
|
|
|
|
|
|
|
nitems = (void**)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
|
|
|
|
for(i=0;i<=max;i++)
|
|
|
|
nitems[i] = da->items[i];
|
|
|
|
|
|
|
|
/* set rest pointers to the NULL */
|
|
|
|
for(i=max+1; i<=da->max_item_index; i++)
|
|
|
|
nitems[i]=NULL;
|
|
|
|
|
|
|
|
MEM_freeN(da->items); /* free old access array */
|
|
|
|
da->items = nitems;
|
|
|
|
}
|
|
|
|
|
|
|
|
da->items[index] = item;
|
|
|
|
da->count++;
|
|
|
|
if(index > da->last_item_index) da->last_item_index = index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free access array */
|
|
|
|
static void destroy_array(DynamicArray *da)
|
|
|
|
{
|
|
|
|
da->count=0;
|
|
|
|
da->last_item_index=0;
|
|
|
|
da->max_item_index=0;
|
|
|
|
MEM_freeN(da->items);
|
|
|
|
da->items = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize dynamic array */
|
|
|
|
static void init_array(DynamicArray *da)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
da->count=0;
|
|
|
|
da->last_item_index=0;
|
|
|
|
da->max_item_index = PAGE_SIZE-1;
|
|
|
|
da->items = (void*)MEM_mallocN(sizeof(void*)*(da->max_item_index+1), "dlist access array");
|
|
|
|
for(i=0; i<=da->max_item_index; i++) da->items[i]=NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reinitialize dynamic array */
|
|
|
|
static void reinit_array(DynamicArray *da)
|
|
|
|
{
|
|
|
|
destroy_array(da);
|
|
|
|
init_array(da);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=====================================================================================*/
|
|
|
|
/* Methods for two way dynamic list with access array */
|
|
|
|
/*=====================================================================================*/
|
|
|
|
|
|
|
|
/* create new two way dynamic list with access array from two way dynamic list
|
|
|
|
* it doesn't copy any items to new array or something like this It is strongly
|
|
|
|
* recomended to use BLI_dlist_ methods for adding/removing items from dynamic list
|
|
|
|
* unless you can end with inconsistence system !!! */
|
|
|
|
DynamicList *BLI_dlist_from_listbase(ListBase *lb)
|
|
|
|
{
|
|
|
|
DynamicList *dlist;
|
|
|
|
Link *item;
|
|
|
|
int i=0, count;
|
|
|
|
|
|
|
|
if(!lb) return NULL;
|
|
|
|
|
|
|
|
count = BLI_countlist(lb);
|
|
|
|
|
|
|
|
dlist = MEM_mallocN(sizeof(DynamicList), "temp dynamic list");
|
|
|
|
/* ListBase stuff */
|
|
|
|
dlist->lb.first = lb->first;
|
|
|
|
dlist->lb.last = lb->last;
|
|
|
|
/* access array stuff */
|
|
|
|
dlist->da.count=count;
|
|
|
|
dlist->da.max_item_index = count-1;
|
|
|
|
dlist->da.last_item_index = count -1;
|
|
|
|
dlist->da.items = (void*)MEM_mallocN(sizeof(void*)*count, "temp dlist access array");
|
|
|
|
|
|
|
|
item = (Link*)lb->first;
|
|
|
|
while(item){
|
|
|
|
dlist->da.items[i] = (void*)item;
|
|
|
|
item = item->next;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* to prevent you of using original ListBase :-) */
|
|
|
|
lb->first = lb->last = NULL;
|
|
|
|
|
|
|
|
return dlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* take out ListBase from DynamicList and destroy all temporary structures of DynamicList */
|
|
|
|
ListBase *BLI_listbase_from_dlist(DynamicList *dlist, ListBase *lb)
|
|
|
|
{
|
|
|
|
if(!dlist) return NULL;
|
|
|
|
|
|
|
|
if(!lb) lb = (ListBase*)MEM_mallocN(sizeof(ListBase), "ListBase");
|
|
|
|
|
|
|
|
lb->first = dlist->lb.first;
|
|
|
|
lb->last = dlist->lb.last;
|
|
|
|
|
|
|
|
/* free all items of access array */
|
|
|
|
MEM_freeN(dlist->da.items);
|
|
|
|
/* free DynamicList*/
|
|
|
|
MEM_freeN(dlist);
|
|
|
|
|
|
|
|
return lb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return pointer at item from th dynamic list with access array */
|
|
|
|
void *BLI_dlist_find_link(DynamicList *dlist, unsigned int index)
|
|
|
|
{
|
|
|
|
if(!dlist || !dlist->da.items) return NULL;
|
|
|
|
|
|
|
|
if((index <= dlist->da.last_item_index) && (index >= 0) && (dlist->da.count>0)){
|
|
|
|
return dlist->da.items[index];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return count of items in the dynamic list with access array */
|
|
|
|
unsigned int BLI_count_items(DynamicList *dlist)
|
|
|
|
{
|
|
|
|
if(!dlist) return 0;
|
|
|
|
|
|
|
|
return dlist->da.count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free item from the dynamic list with access array */
|
|
|
|
void BLI_dlist_free_item(DynamicList *dlist, unsigned int index)
|
|
|
|
{
|
|
|
|
if(!dlist || !dlist->da.items) return;
|
|
|
|
|
|
|
|
if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
|
|
|
|
BLI_freelinkN(&(dlist->lb), dlist->da.items[index]);
|
|
|
|
rem_array_item(&(dlist->da), index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove item from the dynamic list with access array */
|
|
|
|
void BLI_dlist_rem_item(DynamicList *dlist, unsigned int index)
|
|
|
|
{
|
|
|
|
if(!dlist || !dlist->da.items) return;
|
|
|
|
|
|
|
|
if((index <= dlist->da.last_item_index) && (dlist->da.items[index])){
|
|
|
|
BLI_remlink(&(dlist->lb), dlist->da.items[index]);
|
|
|
|
rem_array_item(&(dlist->da), index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add item to the dynamic list with access array (index) */
|
|
|
|
void* BLI_dlist_add_item_index(DynamicList *dlist, void *item, unsigned int index)
|
|
|
|
{
|
|
|
|
if(!dlist || !dlist->da.items) return NULL;
|
|
|
|
|
|
|
|
if((index <= dlist->da.max_item_index) && (dlist->da.items[index])) {
|
|
|
|
/* you can't place item at used index */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
add_array_item(&(dlist->da), item, index);
|
|
|
|
BLI_addtail(&(dlist->lb), item);
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* destroy dynamic list with access array */
|
|
|
|
void BLI_dlist_destroy(DynamicList *dlist)
|
|
|
|
{
|
|
|
|
if(!dlist) return;
|
|
|
|
|
|
|
|
BLI_freelistN(&(dlist->lb));
|
|
|
|
destroy_array(&(dlist->da));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize dynamic list with access array */
|
|
|
|
void BLI_dlist_init(DynamicList *dlist)
|
|
|
|
{
|
|
|
|
if(!dlist) return;
|
|
|
|
|
|
|
|
dlist->lb.first = NULL;
|
|
|
|
dlist->lb.last = NULL;
|
|
|
|
|
|
|
|
init_array(&(dlist->da));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reinitialize dynamic list with acces array */
|
|
|
|
void BLI_dlist_reinit(DynamicList *dlist)
|
|
|
|
{
|
|
|
|
if(!dlist) return;
|
|
|
|
|
|
|
|
BLI_freelistN(&(dlist->lb));
|
|
|
|
reinit_array(&(dlist->da));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*=====================================================================================*/
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2007-09-04 15:53:22 +00:00
|
|
|
char *BLI_strdupn(const char *str, int len) {
|
2002-10-12 11:37:38 +00:00
|
|
|
char *n= MEM_mallocN(len+1, "strdup");
|
|
|
|
memcpy(n, str, len);
|
|
|
|
n[len]= '\0';
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
2007-09-03 19:12:36 +00:00
|
|
|
char *BLI_strdup(const char *str) {
|
2002-10-12 11:37:38 +00:00
|
|
|
return BLI_strdupn(str, strlen(str));
|
|
|
|
}
|
|
|
|
|
2006-12-20 17:57:56 +00:00
|
|
|
char *BLI_strncpy(char *dst, const char *src, int maxncpy) {
|
2002-10-12 11:37:38 +00:00
|
|
|
int srclen= strlen(src);
|
|
|
|
int cpylen= (srclen>(maxncpy-1))?(maxncpy-1):srclen;
|
|
|
|
|
|
|
|
memcpy(dst, src, cpylen);
|
|
|
|
dst[cpylen]= '\0';
|
|
|
|
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2007-03-19 19:34:04 +00:00
|
|
|
int BLI_snprintf(char *buffer, size_t count, const char *format, ...)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
va_list arg;
|
|
|
|
|
|
|
|
va_start(arg, format);
|
|
|
|
n = vsnprintf(buffer, count, format, arg);
|
|
|
|
|
|
|
|
if (n != -1 && n < count) {
|
|
|
|
buffer[n] = '\0';
|
|
|
|
} else {
|
|
|
|
buffer[count-1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end(arg);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
int BLI_streq(char *a, char *b) {
|
|
|
|
return (strcmp(a, b)==0);
|
|
|
|
}
|
|
|
|
int BLI_strcaseeq(char *a, char *b) {
|
2005-04-02 15:36:57 +00:00
|
|
|
return (BLI_strcasecmp(a, b)==0);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2005-12-14 13:21:32 +00:00
|
|
|
/* ******************** string encoding ***************** */
|
|
|
|
|
|
|
|
/* This is quite an ugly function... its purpose is to
|
|
|
|
* take the dir name, make it absolute, and clean it up, replacing
|
|
|
|
* excess file entry stuff (like /tmp/../tmp/../)
|
|
|
|
* note that dir isn't protected for max string names...
|
|
|
|
*/
|
|
|
|
|
|
|
|
void BLI_cleanup_dir(const char *relabase, char *dir)
|
2007-12-31 12:03:26 +00:00
|
|
|
{
|
|
|
|
BLI_cleanup_file(relabase, dir);
|
|
|
|
#ifdef WIN32
|
|
|
|
strcat(dir, "\\");
|
|
|
|
#else
|
|
|
|
strcat(dir, "/");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_cleanup_file(const char *relabase, char *dir)
|
2005-12-14 13:21:32 +00:00
|
|
|
{
|
|
|
|
short a;
|
|
|
|
char *start, *eind;
|
|
|
|
|
|
|
|
BLI_convertstringcode(dir, relabase, 0);
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
if(dir[0]=='.') { /* happens for example in FILE_MAIN */
|
2006-08-20 14:41:13 +00:00
|
|
|
get_default_root(dir);
|
2005-12-14 13:21:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( (start = strstr(dir, "\\..\\")) ) {
|
|
|
|
eind = start + strlen("\\..\\") - 1;
|
|
|
|
a = start-dir-1;
|
|
|
|
while (a>0) {
|
|
|
|
if (dir[a] == '\\') break;
|
|
|
|
a--;
|
|
|
|
}
|
|
|
|
strcpy(dir+a,eind);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( (start = strstr(dir,"\\.\\")) ){
|
|
|
|
eind = start + strlen("\\.\\") - 1;
|
|
|
|
strcpy(start,eind);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( (start = strstr(dir,"\\\\" )) ){
|
|
|
|
eind = start + strlen("\\\\") - 1;
|
|
|
|
strcpy(start,eind);
|
|
|
|
}
|
|
|
|
|
|
|
|
if((a = strlen(dir))){ /* remove the '\\' at the end */
|
|
|
|
while(a>0 && dir[a-1] == '\\'){
|
|
|
|
a--;
|
|
|
|
dir[a] = 0;
|
|
|
|
}
|
|
|
|
}
|
2007-12-31 12:03:26 +00:00
|
|
|
#else
|
2005-12-14 13:21:32 +00:00
|
|
|
if(dir[0]=='.') { /* happens, for example in FILE_MAIN */
|
|
|
|
dir[0]= '/';
|
|
|
|
dir[1]= 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( (start = strstr(dir, "/../")) ) {
|
|
|
|
eind = start + strlen("/../") - 1;
|
|
|
|
a = start-dir-1;
|
|
|
|
while (a>0) {
|
|
|
|
if (dir[a] == '/') break;
|
|
|
|
a--;
|
|
|
|
}
|
|
|
|
strcpy(dir+a,eind);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( (start = strstr(dir,"/./")) ){
|
|
|
|
eind = start + strlen("/./") - 1;
|
|
|
|
strcpy(start,eind);
|
|
|
|
}
|
|
|
|
|
|
|
|
while ( (start = strstr(dir,"//" )) ){
|
|
|
|
eind = start + strlen("//") - 1;
|
|
|
|
strcpy(start,eind);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( (a = strlen(dir)) ){ /* remove all '/' at the end */
|
|
|
|
while(dir[a-1] == '/'){
|
|
|
|
a--;
|
|
|
|
dir[a] = 0;
|
|
|
|
if (a<=0) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-24 20:52:51 +00:00
|
|
|
void BLI_makestringcode(const char *relfile, char *file)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2005-10-24 20:52:51 +00:00
|
|
|
char * p;
|
|
|
|
char * q;
|
|
|
|
char * lslash;
|
|
|
|
char temp[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
char res[FILE_MAXDIR+FILE_MAXFILE];
|
2007-03-17 14:46:04 +00:00
|
|
|
|
2005-12-11 22:03:04 +00:00
|
|
|
/* if file is already relative, bail out */
|
|
|
|
if(file[0]=='/' && file[1]=='/') return;
|
|
|
|
|
2006-08-20 14:41:13 +00:00
|
|
|
/* also bail out if relative path is not set */
|
|
|
|
if (relfile[0] == 0) return;
|
|
|
|
|
2007-02-21 20:00:03 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
if (strlen(relfile) > 2 && relfile[1] != ':') {
|
|
|
|
char* ptemp;
|
|
|
|
/* fix missing volume name in relative base,
|
|
|
|
can happen with old .Blog files */
|
|
|
|
get_default_root(temp);
|
|
|
|
ptemp = &temp[2];
|
|
|
|
if (relfile[0] != '\\' && relfile[0] != '/') {
|
|
|
|
ptemp++;
|
|
|
|
}
|
|
|
|
BLI_strncpy(ptemp, relfile, FILE_MAXDIR + FILE_MAXFILE-3);
|
|
|
|
} else {
|
|
|
|
BLI_strncpy(temp, relfile, FILE_MAXDIR + FILE_MAXFILE);
|
|
|
|
}
|
|
|
|
|
2005-10-24 20:52:51 +00:00
|
|
|
if (strlen(file) > 2) {
|
|
|
|
if ( temp[1] == ':' && file[1] == ':' && temp[0] != file[0] )
|
|
|
|
return;
|
|
|
|
}
|
2007-02-21 20:00:03 +00:00
|
|
|
#else
|
|
|
|
BLI_strncpy(temp, relfile, FILE_MAX);
|
2005-05-20 12:18:11 +00:00
|
|
|
#endif
|
2005-10-24 20:52:51 +00:00
|
|
|
|
|
|
|
BLI_char_switch(temp, '\\', '/');
|
|
|
|
BLI_char_switch(file, '\\', '/');
|
|
|
|
|
|
|
|
/* the last slash in the file indicates where the path part ends */
|
|
|
|
lslash = BLI_last_slash(temp);
|
|
|
|
|
|
|
|
if (lslash)
|
|
|
|
{
|
|
|
|
/* find the prefix of the filename that is equal for both filenames.
|
|
|
|
This is replaced by the two slashes at the beginning */
|
|
|
|
p = temp;
|
|
|
|
q = file;
|
|
|
|
while (*p == *q) {
|
|
|
|
++p; ++q;
|
|
|
|
}
|
|
|
|
/* we might have passed the slash when the beginning of a dir matches
|
|
|
|
so we rewind. Only check on the actual filename
|
|
|
|
*/
|
|
|
|
if (*q != '/') {
|
|
|
|
while ( (q >= file) && (*q != '/') ) { --q; --p; }
|
|
|
|
}
|
|
|
|
else if (*p != '/') {
|
|
|
|
while ( (p >= temp) && (*p != '/') ) { --p; --q; }
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(res, "//");
|
|
|
|
|
|
|
|
/* p now points to the slash that is at the beginning of the part
|
|
|
|
where the path is different from the relative path.
|
|
|
|
We count the number of directories we need to go up in the
|
|
|
|
hierarchy to arrive at the common 'prefix' of the path
|
|
|
|
*/
|
|
|
|
while (p && p < lslash) {
|
|
|
|
if (*p == '/')
|
|
|
|
strcat(res, "../");
|
|
|
|
++p;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2005-10-24 20:52:51 +00:00
|
|
|
|
|
|
|
strcat(res, q+1); /* don't copy the slash at the beginning */
|
2005-12-14 13:21:32 +00:00
|
|
|
|
2005-10-24 20:52:51 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
BLI_char_switch(res+2, '/', '\\');
|
|
|
|
#endif
|
|
|
|
strcpy(file, res);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-14 13:21:32 +00:00
|
|
|
int BLI_convertstringcode(char *path, const char *basepath, int framenum)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2007-03-17 14:46:04 +00:00
|
|
|
int len, wasrelative;
|
2005-05-20 12:18:11 +00:00
|
|
|
char tmp[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
char base[FILE_MAXDIR];
|
2006-09-16 11:42:37 +00:00
|
|
|
char vol[3] = {'\0', '\0', '\0'};
|
|
|
|
|
2006-10-02 16:11:57 +00:00
|
|
|
BLI_strncpy(vol, path, 3);
|
2006-09-16 11:42:37 +00:00
|
|
|
wasrelative= (strncmp(vol, "//", 2)==0);
|
2006-08-20 14:41:13 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2006-09-16 11:42:37 +00:00
|
|
|
/* we are checking here if we have an absolute path that is not in the current
|
|
|
|
blend file as a lib main - we are basically checking for the case that a
|
|
|
|
UNIX root '/' is passed.
|
|
|
|
*/
|
|
|
|
if (!wasrelative && (vol[1] != ':' && (vol[0] == '\0' || vol[0] == '/' || vol[0] == '\\'))) {
|
|
|
|
char *p = path;
|
2006-08-20 14:41:13 +00:00
|
|
|
get_default_root(tmp);
|
|
|
|
// get rid of the slashes at the beginning of the path
|
2006-09-16 11:42:37 +00:00
|
|
|
while (*p == '\\' || *p == '/') {
|
|
|
|
p++;
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
2006-09-16 11:42:37 +00:00
|
|
|
strcat(tmp, p);
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
strcpy(tmp, path);
|
|
|
|
}
|
|
|
|
#else
|
2005-05-20 12:18:11 +00:00
|
|
|
strcpy(tmp, path);
|
2006-08-20 14:41:13 +00:00
|
|
|
#endif
|
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
strcpy(base, basepath);
|
|
|
|
|
|
|
|
/* push slashes into unix mode - strings entering this part are
|
|
|
|
potentially messed up: having both back- and forward slashes.
|
|
|
|
Here we push into one conform direction, and at the end we
|
|
|
|
push them into the system specific dir. This ensures uniformity
|
|
|
|
of paths and solving some problems (and prevent potential future
|
|
|
|
ones) -jesterKing. */
|
|
|
|
BLI_char_switch(tmp, '\\', '/');
|
2006-08-20 14:41:13 +00:00
|
|
|
BLI_char_switch(base, '\\', '/');
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
if (tmp[0] == '/' && tmp[1] == '/') {
|
|
|
|
char *filepart= BLI_strdup(tmp+2); /* skip code */
|
|
|
|
char *lslash= BLI_last_slash(base);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
if (lslash) {
|
2005-05-20 12:18:11 +00:00
|
|
|
int baselen= (int) (lslash-base) + 1;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
memcpy(tmp, base, baselen);
|
|
|
|
strcpy(tmp+baselen, filepart);
|
2002-10-12 11:37:38 +00:00
|
|
|
} else {
|
2005-05-20 12:18:11 +00:00
|
|
|
strcpy(tmp, filepart);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(filepart);
|
|
|
|
}
|
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
len= strlen(tmp);
|
|
|
|
if(len && tmp[len-1]=='#') {
|
|
|
|
sprintf(tmp+len-1, "%04d", framenum);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2006-09-16 11:42:37 +00:00
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
strcpy(path, tmp);
|
|
|
|
#ifdef WIN32
|
|
|
|
/* skip first two chars, which in case of
|
|
|
|
absolute path will be drive:/blabla and
|
|
|
|
in case of relpath //blabla/. So relpath
|
|
|
|
// will be retained, rest will be nice and
|
|
|
|
shiny win32 backward slashes :) -jesterKing
|
|
|
|
*/
|
|
|
|
BLI_char_switch(path+2, '/', '\\');
|
|
|
|
#endif
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
return wasrelative;
|
|
|
|
}
|
|
|
|
|
2007-11-30 10:38:59 +00:00
|
|
|
/* copy di to fi without directory only */
|
2006-12-01 19:52:04 +00:00
|
|
|
void BLI_splitdirstring(char *di, char *fi)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
char *lslash= BLI_last_slash(di);
|
|
|
|
|
|
|
|
if (lslash) {
|
2006-12-01 19:52:04 +00:00
|
|
|
BLI_strncpy(fi, lslash+1, FILE_MAXFILE);
|
2002-10-12 11:37:38 +00:00
|
|
|
*(lslash+1)=0;
|
|
|
|
} else {
|
2006-12-01 19:52:04 +00:00
|
|
|
BLI_strncpy(fi, di, FILE_MAXFILE);
|
2002-10-12 11:37:38 +00:00
|
|
|
di[0]= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char *BLI_gethome(void) {
|
|
|
|
#ifdef __BeOS
|
|
|
|
return "/boot/home/"; /* BeOS 4.5: doubleclick at icon doesnt give home env */
|
|
|
|
|
|
|
|
#elif !defined(WIN32)
|
|
|
|
return getenv("HOME");
|
|
|
|
|
|
|
|
#else /* Windows */
|
|
|
|
char * ret;
|
|
|
|
static char dir[512];
|
|
|
|
|
2004-07-11 21:54:18 +00:00
|
|
|
/* Check for %HOME% env var */
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
ret = getenv("HOME");
|
|
|
|
if(ret) {
|
2005-03-03 20:40:48 +00:00
|
|
|
sprintf(dir, "%s\\.blender", ret);
|
2004-05-10 20:35:46 +00:00
|
|
|
if (BLI_exists(dir)) return dir;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2004-07-11 21:54:18 +00:00
|
|
|
|
|
|
|
/* else, check install dir (path containing blender.exe) */
|
|
|
|
|
|
|
|
BLI_getInstallationDir(dir);
|
|
|
|
|
|
|
|
if (BLI_exists(dir))
|
|
|
|
{
|
2005-03-03 20:40:48 +00:00
|
|
|
strcat(dir,"\\.blender");
|
2004-07-11 21:54:18 +00:00
|
|
|
if (BLI_exists(dir)) return(dir);
|
|
|
|
}
|
|
|
|
|
2003-08-11 18:53:23 +00:00
|
|
|
|
|
|
|
/* add user profile support for WIN 2K / NT */
|
2002-10-12 11:37:38 +00:00
|
|
|
ret = getenv("USERPROFILE");
|
|
|
|
if (ret) {
|
|
|
|
if (BLI_exists(ret)) { /* from fop, also below... */
|
2005-03-03 20:40:48 +00:00
|
|
|
sprintf(dir, "%s\\Application Data\\Blender Foundation\\Blender", ret);
|
2002-10-12 11:37:38 +00:00
|
|
|
BLI_recurdir_fileops(dir);
|
|
|
|
if (BLI_exists(dir)) {
|
2005-03-03 20:40:48 +00:00
|
|
|
strcat(dir,"\\.blender");
|
2004-04-20 19:12:48 +00:00
|
|
|
if(BLI_exists(dir)) return(dir);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-08-11 18:53:23 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
Saving in the Windows dir is less than desirable.
|
|
|
|
Use as a last resort ONLY! (aphex)
|
|
|
|
*/
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
ret = getenv("WINDOWS");
|
|
|
|
if (ret) {
|
|
|
|
if(BLI_exists(ret)) return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = getenv("WINDIR");
|
|
|
|
if (ret) {
|
|
|
|
if(BLI_exists(ret)) return ret;
|
|
|
|
}
|
|
|
|
|
2003-08-11 18:53:23 +00:00
|
|
|
return "C:\\Temp"; /* sheesh! bad, bad, bad! (aphex) */
|
2002-10-12 11:37:38 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
void BLI_clean(char *path)
|
|
|
|
{
|
2005-05-20 12:37:48 +00:00
|
|
|
if(path==0) return;
|
2005-05-20 12:18:11 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
if(path && strlen(path)>2) {
|
|
|
|
BLI_char_switch(path+2, '/', '\\');
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
BLI_char_switch(path, '\\', '/');
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_char_switch(char *string, char from, char to)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2005-05-20 12:37:48 +00:00
|
|
|
if(string==0) return;
|
2002-10-12 11:37:38 +00:00
|
|
|
while (*string != 0) {
|
|
|
|
if (*string == from) *string = to;
|
|
|
|
string++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
void BLI_make_exist(char *dir) {
|
2002-10-12 11:37:38 +00:00
|
|
|
int a;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2005-05-20 12:18:11 +00:00
|
|
|
BLI_char_switch(dir, '/', '\\');
|
2002-10-12 11:37:38 +00:00
|
|
|
#else
|
2005-05-20 12:18:11 +00:00
|
|
|
BLI_char_switch(dir, '\\', '/');
|
2002-10-12 11:37:38 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
a = strlen(dir);
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
while(BLI_exists(dir) == 0){
|
|
|
|
a --;
|
|
|
|
while(dir[a] != '\\'){
|
|
|
|
a--;
|
|
|
|
if (a <= 0) break;
|
|
|
|
}
|
|
|
|
if (a >= 0) dir[a+1] = 0;
|
|
|
|
else {
|
2007-02-28 20:11:10 +00:00
|
|
|
/* defaulting to drive (usually 'C:') of Windows installation */
|
2006-08-20 14:41:13 +00:00
|
|
|
get_default_root(dir);
|
2002-10-12 11:37:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
while(BLI_exist(dir) == 0){
|
|
|
|
a --;
|
|
|
|
while(dir[a] != '/'){
|
|
|
|
a--;
|
|
|
|
if (a <= 0) break;
|
|
|
|
}
|
|
|
|
if (a >= 0) dir[a+1] = 0;
|
|
|
|
else {
|
|
|
|
strcpy(dir,"/");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
void BLI_make_existing_file(char *name)
|
|
|
|
{
|
|
|
|
char di[FILE_MAXDIR], fi[FILE_MAXFILE];
|
|
|
|
|
|
|
|
strcpy(di, name);
|
|
|
|
BLI_splitdirstring(di, fi);
|
|
|
|
|
|
|
|
/* test exist */
|
|
|
|
if (BLI_exists(di) == 0) {
|
|
|
|
BLI_recurdir_fileops(di);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-05 13:09:43 +00:00
|
|
|
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2006-02-11 15:02:23 +00:00
|
|
|
int sl;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
if (!string || !dir || !file) return; /* We don't want any NULLs */
|
|
|
|
|
|
|
|
string[0]= 0; /* ton */
|
2005-06-10 13:12:59 +00:00
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
/* we first push all slashes into unix mode, just to make sure we don't get
|
|
|
|
any mess with slashes later on. -jesterKing */
|
2005-11-05 13:09:43 +00:00
|
|
|
/* constant strings can be passed for those parameters - don't change them - elubie */
|
|
|
|
/*
|
2005-05-20 12:18:11 +00:00
|
|
|
BLI_char_switch(relabase, '\\', '/');
|
|
|
|
BLI_char_switch(dir, '\\', '/');
|
|
|
|
BLI_char_switch(file, '\\', '/');
|
2005-11-05 13:09:43 +00:00
|
|
|
*/
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
/* Resolve relative references */
|
|
|
|
if (relabase && dir[0] == '/' && dir[1] == '/') {
|
|
|
|
char *lslash;
|
|
|
|
|
|
|
|
/* Get the file name, chop everything past the last slash (ie. the filename) */
|
|
|
|
strcpy(string, relabase);
|
|
|
|
|
|
|
|
lslash= (strrchr(string, '/')>strrchr(string, '\\'))?strrchr(string, '/'):strrchr(string, '\\');
|
|
|
|
|
|
|
|
if(lslash) *(lslash+1)= 0;
|
|
|
|
|
|
|
|
dir+=2; /* Skip over the relative reference */
|
|
|
|
}
|
2006-08-20 14:41:13 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
else {
|
|
|
|
if (strlen(dir) >= 2 && dir[1] == ':' ) {
|
|
|
|
BLI_strncpy(string, dir, 3);
|
|
|
|
dir += 2;
|
|
|
|
}
|
|
|
|
else { /* no drive specified */
|
|
|
|
/* first option: get the drive from the relabase if it has one */
|
|
|
|
if (relabase && strlen(relabase) >= 2 && relabase[1] == ':' ) {
|
|
|
|
BLI_strncpy(string, relabase, 3);
|
|
|
|
string[2] = '\\';
|
|
|
|
string[3] = '\0';
|
|
|
|
}
|
|
|
|
else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
|
|
|
|
get_default_root(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ignore leading slashes */
|
|
|
|
while (*dir == '/' || *dir == '\\') dir++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
strcat(string, dir);
|
|
|
|
|
2006-02-11 15:02:23 +00:00
|
|
|
/* Make sure string ends in one (and only one) slash */
|
|
|
|
/* first trim all slashes from the end of the string */
|
|
|
|
sl = strlen(string);
|
|
|
|
while (sl>0 && ( string[sl-1] == '/' || string[sl-1] == '\\') ) {
|
|
|
|
string[sl-1] = '\0';
|
|
|
|
sl--;
|
|
|
|
}
|
|
|
|
/* since we've now removed all slashes, put back one slash at the end. */
|
|
|
|
strcat(string, "/");
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
|
|
|
|
file++;
|
|
|
|
|
|
|
|
strcat (string, file);
|
|
|
|
|
|
|
|
/* Push all slashes to the system preferred direction */
|
2005-06-10 13:12:59 +00:00
|
|
|
BLI_clean(string);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2006-12-20 17:57:56 +00:00
|
|
|
int BLI_testextensie(const char *str, const char *ext)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
short a, b;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
a= strlen(str);
|
|
|
|
b= strlen(ext);
|
|
|
|
|
|
|
|
if(a==0 || b==0 || b>=a) {
|
|
|
|
retval = 0;
|
2005-04-02 15:36:57 +00:00
|
|
|
} else if (BLI_strcasecmp(ext, str + a - b)) {
|
2002-10-12 11:37:38 +00:00
|
|
|
retval = 0;
|
|
|
|
} else {
|
|
|
|
retval = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (retval);
|
|
|
|
}
|
|
|
|
|
2005-03-28 15:29:59 +00:00
|
|
|
|
|
|
|
|
2006-08-20 14:41:13 +00:00
|
|
|
void BLI_split_dirfile(const char *string, char *dir, char *file)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
|
|
|
int a;
|
2007-03-17 14:46:04 +00:00
|
|
|
#ifdef WIN32
|
2006-08-20 14:41:13 +00:00
|
|
|
int sl;
|
|
|
|
short is_relative = 0;
|
2007-11-10 11:45:25 +00:00
|
|
|
char path[FILE_MAX];
|
2007-03-17 14:46:04 +00:00
|
|
|
#endif
|
2006-08-20 14:41:13 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
dir[0]= 0;
|
|
|
|
file[0]= 0;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2007-11-10 11:45:25 +00:00
|
|
|
BLI_strncpy(path, string, FILE_MAX);
|
|
|
|
BLI_char_switch(path, '/', '\\'); /* make sure we have a valid path format */
|
|
|
|
sl = strlen(path);
|
2006-08-20 14:41:13 +00:00
|
|
|
if (sl) {
|
2005-04-02 18:20:03 +00:00
|
|
|
int len;
|
2007-11-10 11:45:25 +00:00
|
|
|
if (path[0] == '/' || path[0] == '\\') {
|
|
|
|
BLI_strncpy(dir, path, FILE_MAXDIR);
|
|
|
|
if (sl > 1 && path[0] == '\\' && path[1] == '\\') is_relative = 1;
|
|
|
|
} else if (sl > 2 && path[1] == ':' && path[2] == '\\') {
|
|
|
|
BLI_strncpy(dir, path, FILE_MAXDIR);
|
2006-08-20 14:41:13 +00:00
|
|
|
} else {
|
|
|
|
BLI_getwdN(dir);
|
|
|
|
strcat(dir,"\\");
|
2007-11-10 11:45:25 +00:00
|
|
|
strcat(dir,path);
|
|
|
|
BLI_strncpy(path,dir,FILE_MAXDIR+FILE_MAXFILE);
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
|
2006-08-20 14:41:13 +00:00
|
|
|
// BLI_exist doesn't recognize a slashed dirname as a dir
|
|
|
|
// check if a trailing slash exists, and remove it. Do not do this
|
|
|
|
// when we are already at root. -jesterKing
|
|
|
|
a = strlen(dir);
|
|
|
|
if(a>=4 && dir[a-1]=='\\') dir[a-1] = 0;
|
|
|
|
|
|
|
|
if (is_relative) {
|
2007-09-18 08:29:18 +00:00
|
|
|
printf("WARNING: BLI_split_dirfile needs absolute dir\n");
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_make_exist(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (S_ISDIR(BLI_exist(dir))) {
|
|
|
|
|
|
|
|
/* copy from end of string into file, to ensure filename itself isn't truncated
|
|
|
|
if string is too long. (aphex) */
|
|
|
|
|
2007-11-10 11:45:25 +00:00
|
|
|
len = FILE_MAXFILE - strlen(path);
|
2006-08-20 14:41:13 +00:00
|
|
|
|
|
|
|
if (len < 0)
|
2007-11-10 11:45:25 +00:00
|
|
|
BLI_strncpy(file,path + abs(len),FILE_MAXFILE);
|
2006-08-20 14:41:13 +00:00
|
|
|
else
|
2007-11-10 11:45:25 +00:00
|
|
|
BLI_strncpy(file,path,FILE_MAXFILE);
|
2006-08-20 14:41:13 +00:00
|
|
|
|
2007-11-10 11:45:25 +00:00
|
|
|
if (strrchr(path,'\\')) {
|
|
|
|
BLI_strncpy(file,strrchr(path,'\\')+1,FILE_MAXFILE);
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
|
|
|
|
if ( (a = strlen(dir)) ) {
|
2006-08-20 14:41:13 +00:00
|
|
|
if (dir[a-1] != '\\') strcat(dir,"\\");
|
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
a = strlen(dir) - 1;
|
|
|
|
while(a>0 && dir[a] != '\\') a--;
|
|
|
|
dir[a + 1] = 0;
|
2007-11-10 11:45:25 +00:00
|
|
|
BLI_strncpy(file, path + strlen(dir),FILE_MAXFILE);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2006-08-20 14:41:13 +00:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
else {
|
2006-08-20 14:41:13 +00:00
|
|
|
/* defaulting to first valid drive hoping it's not empty CD and DVD drives */
|
|
|
|
get_default_root(dir);
|
2002-10-12 11:37:38 +00:00
|
|
|
file[0]=0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (strlen(string)) {
|
|
|
|
if (string[0] == '/') {
|
|
|
|
strcpy(dir, string);
|
|
|
|
} else if (string[1] == ':' && string[2] == '\\') {
|
|
|
|
string+=2;
|
|
|
|
strcpy(dir, string);
|
|
|
|
} else {
|
|
|
|
BLI_getwdN(dir);
|
|
|
|
strcat(dir,"/");
|
|
|
|
strcat(dir,string);
|
2007-03-17 14:46:04 +00:00
|
|
|
strcpy((char *)string,dir);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BLI_make_exist(dir);
|
|
|
|
|
|
|
|
if (S_ISDIR(BLI_exist(dir))) {
|
|
|
|
strcpy(file,string + strlen(dir));
|
|
|
|
|
|
|
|
if (strrchr(file,'/')) strcpy(file,strrchr(file,'/')+1);
|
|
|
|
|
|
|
|
if ( (a = strlen(dir)) ) {
|
|
|
|
if (dir[a-1] != '/') strcat(dir,"/");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a = strlen(dir) - 1;
|
|
|
|
while(dir[a] != '/') a--;
|
|
|
|
dir[a + 1] = 0;
|
|
|
|
strcpy(file, string + strlen(dir));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_getwdN(dir);
|
|
|
|
strcat(dir, "/");
|
|
|
|
file[0] = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2007-02-28 21:37:14 +00:00
|
|
|
|
|
|
|
/* simple appending of filename to dir, does not check for valid path! */
|
|
|
|
void BLI_join_dirfile(char *string, const char *dir, const char *file)
|
|
|
|
{
|
|
|
|
int sl_dir = strlen(dir);
|
|
|
|
BLI_strncpy(string, dir, FILE_MAX);
|
|
|
|
if (sl_dir > FILE_MAX-1) sl_dir = FILE_MAX-1;
|
|
|
|
#ifdef WIN32
|
|
|
|
string[sl_dir] = '\\';
|
|
|
|
#else
|
|
|
|
string[sl_dir] = '/';
|
|
|
|
#endif
|
|
|
|
sl_dir++;
|
|
|
|
if (sl_dir <FILE_MAX) {
|
|
|
|
BLI_strncpy(string + sl_dir, file, FILE_MAX-sl_dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
static int add_win32_extension(char *name)
|
|
|
|
{
|
|
|
|
int retval = 0;
|
|
|
|
int type;
|
|
|
|
|
|
|
|
type = BLI_exist(name);
|
|
|
|
if ((type == 0) || S_ISDIR(type)) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
char filename[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
char ext[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
char *extensions = getenv("PATHEXT");
|
|
|
|
if (extensions) {
|
|
|
|
char *temp;
|
|
|
|
do {
|
|
|
|
strcpy(filename, name);
|
|
|
|
temp = strstr(extensions, ";");
|
|
|
|
if (temp) {
|
|
|
|
strncpy(ext, extensions, temp - extensions);
|
|
|
|
ext[temp - extensions] = 0;
|
|
|
|
extensions = temp + 1;
|
|
|
|
strcat(filename, ext);
|
|
|
|
} else {
|
|
|
|
strcat(filename, extensions);
|
|
|
|
}
|
|
|
|
|
|
|
|
type = BLI_exist(filename);
|
|
|
|
if (type && (! S_ISDIR(type))) {
|
|
|
|
retval = 1;
|
|
|
|
strcpy(name, filename);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (temp);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
retval = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_where_am_i(char *fullname, char *name)
|
|
|
|
{
|
|
|
|
char filename[FILE_MAXDIR+FILE_MAXFILE];
|
|
|
|
char *path, *temp;
|
|
|
|
int len;
|
|
|
|
#ifdef _WIN32
|
|
|
|
char *seperator = ";";
|
|
|
|
char *slash = "\\";
|
|
|
|
#else
|
|
|
|
char *seperator = ":";
|
|
|
|
char *slash = "/";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (name && fullname && strlen(name)) {
|
|
|
|
strcpy(fullname, name);
|
|
|
|
if (name[0] == '.') {
|
|
|
|
// relative path, prepend cwd
|
|
|
|
BLI_getwdN(fullname);
|
|
|
|
len = strlen(fullname);
|
|
|
|
if (len && fullname[len -1] != slash[0]) {
|
|
|
|
strcat(fullname, slash);
|
|
|
|
}
|
|
|
|
strcat(fullname, name);
|
|
|
|
add_win32_extension(fullname);
|
|
|
|
} else if (BLI_last_slash(name)) {
|
|
|
|
// full path
|
|
|
|
strcpy(fullname, name);
|
|
|
|
add_win32_extension(fullname);
|
|
|
|
} else {
|
|
|
|
// search for binary in $PATH
|
|
|
|
path = getenv("PATH");
|
|
|
|
if (path) {
|
|
|
|
do {
|
|
|
|
temp = strstr(path, seperator);
|
|
|
|
if (temp) {
|
|
|
|
strncpy(filename, path, temp - path);
|
|
|
|
filename[temp - path] = 0;
|
|
|
|
path = temp + 1;
|
|
|
|
} else {
|
|
|
|
strncpy(filename, path, sizeof(filename));
|
|
|
|
}
|
|
|
|
len = strlen(filename);
|
|
|
|
if (len && filename[len - 1] != slash[0]) {
|
|
|
|
strcat(filename, slash);
|
|
|
|
}
|
|
|
|
strcat(filename, name);
|
|
|
|
if (add_win32_extension(filename)) {
|
|
|
|
strcpy(fullname, filename);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
|
|
if (strcmp(name, fullname)) {
|
|
|
|
printf("guessing '%s' == '%s'\n", name, fullname);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
// in windows change long filename to short filename because
|
|
|
|
// win2k doesn't know how to parse a commandline with lots of
|
|
|
|
// spaces and double-quotes. There's another solution to this
|
|
|
|
// with spawnv(P_WAIT, bprogname, argv) instead of system() but
|
|
|
|
// that's even uglier
|
|
|
|
GetShortPathName(fullname, fullname, FILE_MAXDIR+FILE_MAXFILE);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
printf("Shortname = '%s'\n", fullname);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-05-12 14:59:08 +00:00
|
|
|
/*
|
|
|
|
* returns absolute path to the app bundle
|
|
|
|
* only useful on OS X
|
|
|
|
*/
|
|
|
|
#ifdef __APPLE__
|
|
|
|
char* BLI_getbundle(void) {
|
|
|
|
CFURLRef bundleURL;
|
|
|
|
CFStringRef pathStr;
|
2004-12-12 13:29:54 +00:00
|
|
|
static char path[MAXPATHLEN];
|
2003-05-12 14:59:08 +00:00
|
|
|
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
|
|
|
|
|
|
|
bundleURL = CFBundleCopyBundleURL(mainBundle);
|
|
|
|
pathStr = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
|
|
|
|
CFStringGetCString(pathStr, path, MAXPATHLEN, kCFStringEncodingASCII);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-11-07 16:27:31 +00:00
|
|
|
/* strcasestr not available in MSVC */
|
|
|
|
char *BLI_strcasestr(const char *s, const char *find)
|
|
|
|
{
|
|
|
|
register char c, sc;
|
|
|
|
register size_t len;
|
|
|
|
|
|
|
|
if ((c = *find++) != 0) {
|
|
|
|
c= tolower(c);
|
|
|
|
len = strlen(find);
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
if ((sc = *s++) == 0)
|
|
|
|
return (NULL);
|
|
|
|
sc= tolower(sc);
|
|
|
|
} while (sc != c);
|
|
|
|
} while (BLI_strncasecmp(s, find, len) != 0);
|
|
|
|
s--;
|
|
|
|
}
|
|
|
|
return ((char *) s);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-02 15:36:57 +00:00
|
|
|
int BLI_strcasecmp(const char *s1, const char *s2) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; ; i++) {
|
|
|
|
char c1 = tolower(s1[i]);
|
|
|
|
char c2 = tolower(s2[i]);
|
|
|
|
|
|
|
|
if (c1<c2) {
|
|
|
|
return -1;
|
|
|
|
} else if (c1>c2) {
|
|
|
|
return 1;
|
|
|
|
} else if (c1==0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int BLI_strncasecmp(const char *s1, const char *s2, int n) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
char c1 = tolower(s1[i]);
|
|
|
|
char c2 = tolower(s2[i]);
|
|
|
|
|
|
|
|
if (c1<c2) {
|
|
|
|
return -1;
|
|
|
|
} else if (c1>c2) {
|
|
|
|
return 1;
|
|
|
|
} else if (c1==0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
|
2007-09-02 17:25:03 +00:00
|
|
|
|
|
|
|
#ifdef WITH_ICONV
|
|
|
|
#include "iconv.h"
|
|
|
|
#include "localcharset.h"
|
|
|
|
|
|
|
|
void BLI_string_to_utf8(char *original, char *utf_8, char *code)
|
|
|
|
{
|
|
|
|
size_t inbytesleft=strlen(original);
|
|
|
|
size_t outbytesleft=512;
|
|
|
|
size_t rv=0;
|
|
|
|
iconv_t cd;
|
|
|
|
|
|
|
|
if (NULL == code) {
|
|
|
|
code = locale_charset();
|
|
|
|
}
|
|
|
|
cd=iconv_open("UTF-8", code);
|
|
|
|
|
|
|
|
if (cd == (iconv_t)(-1)) {
|
|
|
|
printf("iconv_open Error");
|
|
|
|
*utf_8='\0';
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
rv=iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
|
|
|
|
if (rv == (size_t) -1) {
|
|
|
|
printf("iconv Error\n");
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
*utf_8 = '\0';
|
|
|
|
iconv_close(cd);
|
|
|
|
}
|
|
|
|
#endif // WITH_ICONV
|
|
|
|
|
2007-12-13 15:06:02 +00:00
|
|
|
void BLI_timestr(double _time, char *str)
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
{
|
|
|
|
/* format 00:00:00.00 (hr:min:sec) string has to be 12 long */
|
2007-12-13 15:06:02 +00:00
|
|
|
int hr= ( (int) _time) / (60*60);
|
|
|
|
int min= (((int) _time) / 60 ) % 60;
|
|
|
|
int sec= ( (int) (_time)) % 60;
|
|
|
|
int hun= ( (int) (_time * 100.0)) % 100;
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
|
|
|
|
if (hr) {
|
|
|
|
sprintf(str, "%.2d:%.2d:%.2d.%.2d",hr,min,sec,hun);
|
|
|
|
} else {
|
|
|
|
sprintf(str, "%.2d:%.2d.%.2d",min,sec,hun);
|
|
|
|
}
|
|
|
|
|
|
|
|
str[11]=0;
|
|
|
|
}
|
|
|
|
|
2007-04-28 16:15:00 +00:00
|
|
|
/* ************** 64 bits magic, trick to support up to 32 gig of address space *************** */
|
|
|
|
/* only works for malloced pointers (8 aligned) */
|
|
|
|
|
|
|
|
#ifdef __LP64__
|
|
|
|
|
|
|
|
#if defined(WIN32) && !defined(FREE_WINDOWS)
|
|
|
|
#define PMASK 0x07FFFFFFFFi64
|
|
|
|
#else
|
|
|
|
#define PMASK 0x07FFFFFFFFll
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
int BLI_int_from_pointer(void *poin)
|
|
|
|
{
|
|
|
|
long lval= (long)poin;
|
|
|
|
|
|
|
|
return (int)(lval>>3);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *BLI_pointer_from_int(int val)
|
|
|
|
{
|
|
|
|
static int firsttime= 1;
|
|
|
|
static long basevalue= 0;
|
|
|
|
|
|
|
|
if(firsttime) {
|
|
|
|
void *poin= malloc(10000);
|
|
|
|
basevalue= (long)poin;
|
|
|
|
basevalue &= ~PMASK;
|
|
|
|
printf("base: %d pointer %p\n", basevalue, poin); /* debug */
|
|
|
|
firsttime= 0;
|
|
|
|
free(poin);
|
|
|
|
}
|
2007-04-29 10:49:02 +00:00
|
|
|
return (void *)(basevalue | (((long)val)<<3));
|
2007-04-28 16:15:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
int BLI_int_from_pointer(void *poin)
|
|
|
|
{
|
|
|
|
return (int)poin;
|
|
|
|
}
|
|
|
|
void *BLI_pointer_from_int(int val)
|
|
|
|
{
|
|
|
|
return (void *)val;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
|